在系统与系统的数据交互中,有些敏感数据是不能直接明文传输的,所以在发送数据之前要进行加密,在接收到数据时进行解密处理;然而由于系统与系统之间的开发语言不同。本次需求是生成二维码是通过java生成,由php来解密。基于这类需求所以选择了RSA进行加解密。 一、生成RSA公私钥
分成三步生成RSA公私钥,第1、2步可以满足php的使用,由于java的私钥要转化为PKCS8格式才能使用,所以执行第三步来实现
1、生成私钥
openssl genrsa -out rsa_private_key.pem 1024
如下:
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDOU3dwYw5oh4qzNv7YcgD0gxrqvGv3nFMbBFvXPDVuy/2AZsJC
OurkwjveVcq2AdtAc+RD409uwNgrf0f6pxl60cNF81qHujCqmrIjPyyokpXwCjBj
L9NlG3RmZ3btN87LDeKvIQt6n85pULOUVyOI7qlCvN8y3zlgsEM41Xqx1wIDAQAB
AoGAK0gvIhBlkV/9pKLAyz7/HEv0dZGZRJQyitRbP8eNnfSE9U6ZKbOaWuq0DGwK
3it9hwPIusUQgLdLobRNsTMkkNJRfPAnuUelZVwAkkNPwN4i4uZAqvifhkoFM7Dt
3pUlNMyxBRVwg6zdjYr26x0AZy+FdGU8QE/cofPT6j6dOIECQQD91itWOzufUKxj
/os89HCWtOs74VxsDiLW/GSQJFp9/+UHSSrbcPuS6t4d0dE6oi9byjUPC10O1Jmc
AJa60CpxAkEA0BWjCXvHdiRZp0jkIg+fLtSPjCzj4ePRP0OwF8vXawIudoO8A6fh
8Fa5l6ZJG9gLl0EAOM1AeO6v+wzRR5b0xwJAJs8r6Q89WmpXMSKl3zfwTtpybMFU
BCFVKlGEfpVQUJtjRO3m444uqJPISf7eYnyRiRMtcZNnMvFGWxer8/wHwQJBAIal
+aIhXqisTPday4Te5vq+wUTLp4p8iOKPQlujo/myp645AGi9Mg77j4z6JUTHQHjX
rvUSnC2lBmtFmAbjP/ECQQCL1a2QUUVS8MynYvUinnkwPedqqC/mWBgSgO0ytatA
T+Stue6pYPvdpqK5iLncrgTPZxUTYA8ulvCM6oewXfl/
-----END RSA PRIVATE KEY-----
2、生成公钥
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOU3dwYw5oh4qzNv7YcgD0gxrq
vGv3nFMbBFvXPDVuy/2AZsJCOurkwjveVcq2AdtAc+RD409uwNgrf0f6pxl60cNF
81qHujCqmrIjPyyokpXwCjBjL9NlG3RmZ3btN87LDeKvIQt6n85pULOUVyOI7qlC
vN8y3zlgsEM41Xqx1wIDAQAB
-----END PUBLIC KEY-----
3、将RSA私钥转换成PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAM5Td3BjDmiHirM2
/thyAPSDGuq8a/ecUxsEW9c8NW7L/YBmwkI66uTCO95VyrYB20Bz5EPjT27A2Ct/
R/qnGXrRw0XzWoe6MKqasiM/LKiSlfAKMGMv02UbdGZndu03zssN4q8hC3qfzmlQ
s5RXI4juqUK83zLfOWCwQzjVerHXAgMBAAECgYArSC8iEGWRX/2kosDLPv8cS/R1
kZlElDKK1Fs/x42d9IT1Tpkps5pa6rQMbAreK32HA8i6xRCAt0uhtE2xMySQ0lF8
8Ce5R6VlXACSQ0/A3iLi5kCq+J+GSgUzsO3elSU0zLEFFXCDrN2NivbrHQBnL4V0
ZTxAT9yh89PqPp04gQJBAP3WK1Y7O59QrGP+izz0cJa06zvhXGwOItb8ZJAkWn3/
5QdJKttw+5Lq3h3R0TqiL1vKNQ8LXQ7UmZwAlrrQKnECQQDQFaMJe8d2JFmnSOQi
D58u1I+MLOPh49E/Q7AXy9drAi52g7wDp+HwVrmXpkkb2AuXQQA4zUB47q/7DNFH
lvTHAkAmzyvpDz1aalcxIqXfN/BO2nJswVQEIVUqUYR+lVBQm2NE7ebjji6ok8hJ
/t5ifJGJEy1xk2cy8UZbF6vz/AfBAkEAhqX5oiFeqKxM91rLhN7m+r7BRMuninyI
4o9CW6Oj+bKnrjkAaL0yDvuPjPolRMdAeNeu9RKcLaUGa0WYBuM/8QJBAIvVrZBR
RVLwzKdi9SKeeTA952qoL+ZYGBKA7TK1q0BP5K257qlg+92mormIudyuBM9nFRNg
Dy6W8Izqh7Bd+X8=
-----END PRIVATE KEY-----
二、PHP实现RSA的加密解密。
<?php
namespace Home\Controller;
use Think\Controller;
class TestController extends Controller {
public function index(){
//2018000000&sh001&u001&223.2&2
//订单号&商户标识&用户标识&实际支付金额&支付方式
$private_key = "-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDOU3dwYw5oh4qzNv7YcgD0gxrqvGv3nFMbBFvXPDVuy/2AZsJC
OurkwjveVcq2AdtAc+RD409uwNgrf0f6pxl60cNF81qHujCqmrIjPyyokpXwCjBj
L9NlG3RmZ3btN87LDeKvIQt6n85pULOUVyOI7qlCvN8y3zlgsEM41Xqx1wIDAQAB
AoGAK0gvIhBlkV/9pKLAyz7/HEv0dZGZRJQyitRbP8eNnfSE9U6ZKbOaWuq0DGwK
3it9hwPIusUQgLdLobRNsTMkkNJRfPAnuUelZVwAkkNPwN4i4uZAqvifhkoFM7Dt
3pUlNMyxBRVwg6zdjYr26x0AZy+FdGU8QE/cofPT6j6dOIECQQD91itWOzufUKxj
/os89HCWtOs74VxsDiLW/GSQJFp9/+UHSSrbcPuS6t4d0dE6oi9byjUPC10O1Jmc
AJa60CpxAkEA0BWjCXvHdiRZp0jkIg+fLtSPjCzj4ePRP0OwF8vXawIudoO8A6fh
8Fa5l6ZJG9gLl0EAOM1AeO6v+wzRR5b0xwJAJs8r6Q89WmpXMSKl3zfwTtpybMFU
BCFVKlGEfpVQUJtjRO3m444uqJPISf7eYnyRiRMtcZNnMvFGWxer8/wHwQJBAIal
+aIhXqisTPday4Te5vq+wUTLp4p8iOKPQlujo/myp645AGi9Mg77j4z6JUTHQHjX
rvUSnC2lBmtFmAbjP/ECQQCL1a2QUUVS8MynYvUinnkwPedqqC/mWBgSgO0ytatA
T+Stue6pYPvdpqK5iLncrgTPZxUTYA8ulvCM6oewXfl/
-----END RSA PRIVATE KEY-----";
$public_key = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOU3dwYw5oh4qzNv7YcgD0gxrq
vGv3nFMbBFvXPDVuy/2AZsJCOurkwjveVcq2AdtAc+RD409uwNgrf0f6pxl60cNF
81qHujCqmrIjPyyokpXwCjBjL9NlG3RmZ3btN87LDeKvIQt6n85pULOUVyOI7qlC
vN8y3zlgsEM41Xqx1wIDAQAB
-----END PUBLIC KEY-----";
//加密
$pi_key = openssl_pkey_get_private($private_key);// 可用返回资源id
$pu_key = openssl_pkey_get_public($public_key);
$data = '{"e":"sign_check_fail","c":2}';
openssl_public_encrypt($data, $encrypted, $pu_key);//公钥加密
//dump ($this->urlsafe_b64encode($encrypted));
//解密
$d = $this->urlsafe_b64decode(I("data"));
$pi_key = openssl_pkey_get_private($private_key);// 可用返回资源id
openssl_private_decrypt($d, $decrypted, $pi_key);//私钥解密
echo $decrypted;
}
//url base64解码
function urlsafe_b64decode($string) {
$data = str_replace(array('-','_'),array('+','/'),$string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
//url base64编码
function urlsafe_b64encode($string) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
}
?>
三、java实现RSA的加密解密。
import org.apache.commons.lang.*;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class RSAUtils {
public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
private static String RSA = "RSA";
public static KeyPair generateRSAKeyPair() {
return generateRSAKeyPair(1024);
}
public static KeyPair generateRSAKeyPair(int keyLength) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
kpg.initialize(keyLength);
return kpg.genKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
public static byte[] encryptData(byte[] data, PublicKey publicKey) {
try {
byte[] dataReturn = new byte[0];
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 加密时超过117字节就报错。为此采用分段加密的办法来加密
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.length; i += 100) {
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i,
i + 100));
sb.append(new String(doFinal));
dataReturn = ArrayUtils.addAll(dataReturn, doFinal);
}
return dataReturn;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 验证数字签名函数入口
*
* @param plainBytes 待验签明文字节数组
* @param signBytes 待验签签名后字节数组
* @param publicKey 验签使用公钥
* @return 验签是否通过
* @throws Exception
*/
public static boolean verifyDigitalSign(byte[] plainBytes, byte[] signBytes, PublicKey publicKey) throws Exception {
boolean isValid = false;
try {
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initVerify(publicKey);
signature.update(plainBytes);
isValid = signature.verify(signBytes);
return isValid;
} catch (NoSuchAlgorithmException e) {
throw new Exception(String.format("验证数字签名时没有[%s]此类算法", SIGN_ALGORITHMS));
} catch (InvalidKeyException e) {
throw new Exception("验证数字签名时公钥无效");
} catch (SignatureException e) {
throw new Exception("验证数字签名时出现异常");
}
}
public static String rsaSign(byte[] encryptByte, PrivateKey privateKey) {
try {
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initSign(privateKey);
signature.update(encryptByte);
byte[] signed = signature.sign();
return (new BASE64Encoder()).encodeBuffer(signed);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] decryptData(byte[] encryptedData, PrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance(RSA);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 解密时超过128字节就报错。为此采用分段解密的办法来解密
byte[] dataReturn = new byte[0];
for (int i = 0; i < encryptedData.length; i += 128) {
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(encryptedData, i,
i + 128));
dataReturn = ArrayUtils.addAll(dataReturn, doFinal);
}
return dataReturn;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static boolean doCheck(byte[] encryptByte, byte[] bs, PublicKey publicKey) {
try {
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initVerify(publicKey);
signature.update(encryptByte);
return signature.verify(bs);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException,
InvalidKeySpecException {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException,
InvalidKeySpecException {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
public static PublicKey getPublicKey(String modulus, String publicExponent)
throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger bigIntModulus = new BigInteger(modulus);
BigInteger bigIntPrivateExponent = new BigInteger(publicExponent);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
public static PrivateKey getPrivateKey(String modulus, String privateExponent)
throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger bigIntModulus = new BigInteger(modulus);
BigInteger bigIntPrivateExponent = new BigInteger(privateExponent);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigIntModulus, bigIntPrivateExponent);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {
byte[] buffer = (new BASE64Decoder()).decodeBuffer(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return keyFactory.generatePublic(keySpec);
}
public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
byte[] buffer = (new BASE64Decoder()).decodeBuffer(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
return keyFactory.generatePrivate(keySpec);
}
public static PublicKey loadPublicKey(InputStream in) throws Exception {
return loadPublicKey(readKey(in));
}
public static PrivateKey loadPrivateKey(InputStream in) throws Exception {
return loadPrivateKey(readKey(in));
}
private static String readKey(InputStream in) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
return sb.toString();
}
public static String urlsafe_encode (String encryptStr){
return encryptStr.replaceAll("\\+","-").replaceAll("/","_").replaceAll("=","").replaceAll("(\r\n|\r|\n|\n\r)","");
}
public static String urlsafe_decode(String encryptStr){
encryptStr= encryptStr.replaceAll("-","+").replaceAll("_","/");
int mob = encryptStr.length()%4;
if(mob>0){
encryptStr+="====".substring(mob);
}
return encryptStr;
}
public static void main(String[ ] asdfs) throws Exception {
String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOU3dwYw5oh4qzNv7YcgD0gxrqvGv3nFMbBFvXPDVuy/2AZsJCOurkwjveVcq2AdtAc+RD409uwNgrf0f6pxl60cNF81qHujCqmrIjPyyokpXwCjBjL9NlG3RmZ3btN87LDeKvIQt6n85pULOUVyOI7qlCvN8y3zlgsEM41Xqx1wIDAQAB";
String privateKeyStr = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAM5Td3BjDmiHirM2/thyAPSDGuq8a/ecUxsEW9c8NW7L/YBmwkI66uTCO95VyrYB20Bz5EPjT27A2Ct/R/qnGXrRw0XzWoe6MKqasiM/LKiSlfAKMGMv02UbdGZndu03zssN4q8hC3qfzmlQs5RXI4juqUK83zLfOWCwQzjVerHXAgMBAAECgYArSC8iEGWRX/2kosDLPv8cS/R1kZlElDKK1Fs/x42d9IT1Tpkps5pa6rQMbAreK32HA8i6xRCAt0uhtE2xMySQ0lF88Ce5R6VlXACSQ0/A3iLi5kCq+J+GSgUzsO3elSU0zLEFFXCDrN2NivbrHQBnL4V0ZTxAT9yh89PqPp04gQJBAP3WK1Y7O59QrGP+izz0cJa06zvhXGwOItb8ZJAkWn3/5QdJKttw+5Lq3h3R0TqiL1vKNQ8LXQ7UmZwAlrrQKnECQQDQFaMJe8d2JFmnSOQiD58u1I+MLOPh49E/Q7AXy9drAi52g7wDp+HwVrmXpkkb2AuXQQA4zUB47q/7DNFHlvTHAkAmzyvpDz1aalcxIqXfN/BO2nJswVQEIVUqUYR+lVBQm2NE7ebjji6ok8hJ/t5ifJGJEy1xk2cy8UZbF6vz/AfBAkEAhqX5oiFeqKxM91rLhN7m+r7BRMuninyI4o9CW6Oj+bKnrjkAaL0yDvuPjPolRMdAeNeu9RKcLaUGa0WYBuM/8QJBAIvVrZBRRVLwzKdi9SKeeTA952qoL+ZYGBKA7TK1q0BP5K257qlg+92mormIudyuBM9nFRNgDy6W8Izqh7Bd+X8=";
PublicKey publicKey = RSAUtils.loadPublicKey(publicKeyStr);
PrivateKey privateKey = RSAUtils.loadPrivateKey(privateKeyStr);
//加密
String data = "{\"content\":\"test_rsa_encode\",\"reault\":1}";
System.out.println(data);
String encryptStr = (new BASE64Encoder()).encodeBuffer(RSAUtils.encryptData(data.getBytes(), publicKey));
System.out.println(encryptStr);
encryptStr = urlsafe_encode(encryptStr);
System.out.println(encryptStr);
encryptStr = urlsafe_decode(encryptStr);
System.out.println(encryptStr);
//解密
System.out.println(new String(RSAUtils.decryptData((new BASE64Decoder()).decodeBuffer(encryptStr), privateKey)));
}
四、javascript rsa加解密
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="jsencrypt.js"></script>
</head>
<body>
<script>
String.prototype.replaceAllStr=function(f,e){
var reg=new RegExp(f,"g");
return this.replace(reg,e);
}
function urlsafeEncode(e) {
return e.replaceAllStr("\\+","-").replaceAllStr("/","_").replaceAllStr("=","");
}
function urlsafeDecode(e) {
e = e.replaceAllStr("-","+").replaceAllStr("_","/");
var mob = e.length%4;
if(mob>0){
e += "====".substr(mob);
}
return e;
}
// java后台生成的
var publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOU3dwYw5oh4qzNv7YcgD0gxrqvGv3nFMbBFvXPDVuy/2AZsJCOurkwjveVcq2AdtAc+RD409uwNgrf0f6pxl60cNF81qHujCqmrIjPyyokpXwCjBjL9NlG3RmZ3btN87LDeKvIQt6n85pULOUVyOI7qlCvN8y3zlgsEM41Xqx1wIDAQAB";;
var privateKeyStr = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAM5Td3BjDmiHirM2/thyAPSDGuq8a/ecUxsEW9c8NW7L/YBmwkI66uTCO95VyrYB20Bz5EPjT27A2Ct/R/qnGXrRw0XzWoe6MKqasiM/LKiSlfAKMGMv02UbdGZndu03zssN4q8hC3qfzmlQs5RXI4juqUK83zLfOWCwQzjVerHXAgMBAAECgYArSC8iEGWRX/2kosDLPv8cS/R1kZlElDKK1Fs/x42d9IT1Tpkps5pa6rQMbAreK32HA8i6xRCAt0uhtE2xMySQ0lF88Ce5R6VlXACSQ0/A3iLi5kCq+J+GSgUzsO3elSU0zLEFFXCDrN2NivbrHQBnL4V0ZTxAT9yh89PqPp04gQJBAP3WK1Y7O59QrGP+izz0cJa06zvhXGwOItb8ZJAkWn3/5QdJKttw+5Lq3h3R0TqiL1vKNQ8LXQ7UmZwAlrrQKnECQQDQFaMJe8d2JFmnSOQiD58u1I+MLOPh49E/Q7AXy9drAi52g7wDp+HwVrmXpkkb2AuXQQA4zUB47q/7DNFHlvTHAkAmzyvpDz1aalcxIqXfN/BO2nJswVQEIVUqUYR+lVBQm2NE7ebjji6ok8hJ/t5ifJGJEy1xk2cy8UZbF6vz/AfBAkEAhqX5oiFeqKxM91rLhN7m+r7BRMuninyI4o9CW6Oj+bKnrjkAaL0yDvuPjPolRMdAeNeu9RKcLaUGa0WYBuM/8QJBAIvVrZBRRVLwzKdi9SKeeTA952qoL+ZYGBKA7TK1q0BP5K257qlg+92mormIudyuBM9nFRNgDy6W8Izqh7Bd+X8=";
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
var encryptStr= encrypt.encrypt("test")
var urlsafe = urlsafeEncode(encryptStr);
// 加密
document.write("<br/>");
document.write(urlsafe);
//解密
encrypt.setPrivateKey(privateKeyStr);
var decryptStr = encrypt.decrypt(urlsafeDecode(urlsafe));
document.write("<br/>");
document.write(decryptStr);
</script>
</body>
</html>
验证:通过java生成的密文:
doKFqNWXi6oEoURhYboPgEGsuQ34f8sYR3QmrePdPhE5x6GgemYjGM3iTiwhDtBuIc4_caZ2nGm0qJ82NLwQQdS4eaXr-ioKpfR_F06CmE2TU69FFjwuPwwlk6xdOfYPJan8rqQGcVdmqa0Ig04dA-M1Dkif8WAZ6mYUKb30aLA
再通过php进行解密