RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定RSA的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。
RSA的安全基于大数分解的难度。其公钥和私钥是一对大素数(100到200位十进制数或更大)的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积(这是公认的数学难题)。
RSA的公钥、私钥的组成,以及加密、解密的公式可见于下表:
版本
语言 | 版本 |
---|
PHP | 7.3.11 |
Java | 1.8.0_231 |
密钥生成
PHP
RSAUtils::resetGenKeyPair
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static function resetGenKeyPair() { $config = array( "private_key_bits" => self::PRIVATE_KEY_BITS, "private_key_type" => self::KEY_ALGORITHM, );
$openssl = openssl_pkey_new($config); openssl_pkey_export($openssl, $privateKey); $publicKey = openssl_pkey_get_details($openssl); $publicKey = $publicKey["key"];
return [ 'publicKey' => $publicKey, 'privateKey' => $privateKey, 'publicKeyStr' => self::key2str($publicKey), 'privateKeyStr' => self::key2str($privateKey) ]; }
|
Java
RSAUtils.resetGenKeyPair
1 2 3 4 5 6 7 8 9 10 11 12 13
| static Map<String, Object> resetGenKeyPair() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; }
|
签名
私钥加签。
有时签名可能会因为数据编码不同而导致不一致,所以要求 PHP 和 Java 都对数据进行编码处理。
PHP
RSAUtils::sign
1 2 3 4 5 6 7 8
| public static function sign($dataStr, $privateKey) { $dataStr = self::str2utf8($dataStr); $privateKeyId = openssl_get_privatekey($privateKey); openssl_sign($dataStr, $sign, $privateKeyId, self::SIGNATURE_ALGORITHM); openssl_free_key($privateKeyId); return base64_encode($sign); }
|
Java
RSAUtils.sign
1 2 3 4 5 6 7 8 9 10 11 12
| static String sign(String data, String privateKey) throws Exception { byte[] keyBytes = Base64.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateK); signature.update(data.getBytes(ENCODING)); return Base64.encodeToString(signature.sign()); }
|
验签
公钥验签。
PHP
RSAUtils::verifySign
1 2 3 4 5 6
| public static function verifySign($dataStr, $publicKey, $sign) { $dataStr = self::str2utf8($dataStr); $publicKeyId = openssl_get_publickey($publicKey); return (boolean) openssl_verify($dataStr, base64_decode($sign), $publicKeyId, self::SIGNATURE_ALGORITHM); }
|
Java
RSAUtils.verifySign
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| static boolean verifySign(String data, String publicKey, String sign) throws Exception { try { byte[] keyBytes = Base64.decode(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicK); signature.update(data.getBytes(ENCODING));
return signature.verify(Base64.decode(sign)); } catch (Exception e) { throw e; } }
|
加密
公钥加密
PHP
RSAUtils::encryptByPublicKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static function encryptByPublicKey($dataStr, $publicKey) { $dataStr = self::str2utf8($dataStr); $publicKeyId = openssl_get_publickey($publicKey); $data = "";
$dataArray = str_split($dataStr, self::PRIVATE_KEY_BITS / 8 - 11); foreach ($dataArray as $value) { openssl_public_encrypt($value,$encryptedTemp, $publicKeyId,self::EN_DE_ALGORITHM); $data .= $encryptedTemp; } openssl_free_key($publicKeyId); return base64_encode($data); }
|
Java
RSAUtils.encryptByPublicKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| static String encryptByPublicKey(String dataStr, String publicKey) throws Exception { byte[] data = dataStr.getBytes(ENCODING); byte[] keyBytes = Base64.decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0; byte[] cache; int i = 0; while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); return Base64.encodeToString(encryptedData); }
|
私钥加密
PHP
RSAUtils::encryptByPrivateKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static function encryptByPrivateKey($dataStr, $privateKey) { $dataStr = self::str2utf8($dataStr); $privateKeyId = openssl_get_privatekey($privateKey); $data = "";
$dataArray = str_split($dataStr, self::PRIVATE_KEY_BITS / 8 - 11); foreach ($dataArray as $value) { openssl_private_encrypt($value,$encryptedTemp, $privateKeyId,self::EN_DE_ALGORITHM); $data .= $encryptedTemp; } openssl_free_key($privateKeyId); return base64_encode($data); }
|
Java
RSAUtils.encryptByPrivateKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| static String encryptByPrivateKey(String dataStr, String privateKey) throws Exception { byte[] data = dataStr.getBytes(ENCODING); byte[] keyBytes = Base64.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0; byte[] cache; int i = 0; while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); return Base64.encodeToString(encryptedData); }
|
解密
公钥解密
PHP
RSAUtils::decryptByPublicKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static function decryptByPublicKey($encryptData, $publicKey) { $decrypted = ""; $decodeStr = base64_decode($encryptData); $publicKeyId = openssl_get_publickey($publicKey);
$enArray = str_split($decodeStr, self::PRIVATE_KEY_BITS / 8);
foreach ($enArray as $value) { openssl_public_decrypt($value,$decryptedTemp, $publicKeyId,self::EN_DE_ALGORITHM); $decrypted .= $decryptedTemp; } openssl_free_key($publicKeyId); return $decrypted; }
|
Java
RSAUtils.decryptByPublicKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| static String decryptByPublicKey(String encryptedDataStr, String publicKey) throws Exception { byte[] encryptedData = Base64.decode(encryptedDataStr); byte[] keyBytes = Base64.decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0; byte[] cache; int i = 0; while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return new String(decryptedData, ENCODING); }
|
私钥解密
PHP
RSAUtils::decryptByPrivateKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public static function decryptByPrivateKey($encryptData, $private) { $decrypted = ""; $decodeStr = base64_decode($encryptData); $privateKeyId = openssl_get_privatekey($private);
$enArray = str_split($decodeStr, self::PRIVATE_KEY_BITS / 8);
foreach ($enArray as $value) { openssl_private_decrypt($value,$decryptedTemp, $privateKeyId,self::EN_DE_ALGORITHM); $decrypted .= $decryptedTemp; } openssl_free_key($privateKeyId); return $decrypted; }
|
Java
RSAUtils.decryptByPrivateKey
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| static String decryptByPrivateKey(String encryptedDataStr, String privateKey) throws Exception { byte[] encryptedData = Base64.decode(encryptedDataStr); byte[] keyBytes = Base64.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0; byte[] cache; int i = 0; while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return new String(decryptedData, ENCODING); }
|
Demo
完整 Demo 源码:BNDong/demo/PhpJavaRsa