系统与系统的数据交互中,有些敏感数据是不能直接明文传输的,所以在发送数据之前要进行加密,在接收到数据时进行解密处理;然而由于系统与系统之间的开发语言不同。
本次需求是生成二维码是通过java生成,由php来解密。基于这类需求所以选择了RSA进行加解密。
生成RSA公私钥分成三步生成,第1、2步可以满足php的使用,由于java的私钥要转化为PKCS8格式才能使用,所以执行第3步来实现。
还有一种加密方式参考: DES ECB 模式 JAVA PHP C# 实现 加密 解密 兼容 。
1、生成私钥
openssl genrsa -out rsa_private_key.pem 1024
如下:
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC6BSDlbRplhMMNZBKHX4xe8AwESpzHVfAcHHsX9FFSMuF91W3c
xgT/g5n+qlLLFzCE3hWG/yX5NMAxR4mS3MlhyXKwko3tK9Ua691afod1lxORR3Ia
Z8nV7v5Bv8y4JDe4E3/f/bQIGzroWiJ0sXTcO41GqvOw3G9leClSvjVnSwIDAQAB
AoGAagooYYCbTomq4wRL562ZCDmQsBWUX7Fmia/Wn6YfgVsN3bx/vx2Gld2AOIMB
ZVJXzzYGUYk7LV9bu/vKudRwWvtPIYzxPEOBoaFGPrEPTAfDVwOklhzTz3zDmCHi
hLSpjQXYCG7boZ6G96NfKyTRSGPqgovHY3+KJvd/gAoZqOkCQQDt9YXfanpuwZx1
7MYjMEvoh5UY1vSsV72ts3/gTVEUkWdfXHj0XhyRhOL9Qu99TGZcoEwecygoUPLm
dySyiXl/AkEAyB+JP8W7oTG/HTHc5QGDfwlPjIH1o5YG2I8Tp02i3G7OTJc/b9/+
SPxcKsT78xrgox5ModPKBX50F783Y2DANQJBAKY4Mjp882b4gWVybnlYHD4ir0h5
ptHYPFvgnfu9plx6sT3Qp4DzWHth2vlUT1w0CPC83E8M28lFula4dP7tvtsCQQCt
a2asdNVbophS3FrnuKAS/iaJRDVxRRk5oQMPACAZlYwAozC96gWZidb02S7cRHZV
5HPT6IwwppxD19hPrg/hAkBdnl+BGF/eRw80OHJtZBkLnY4Hx9YGft9AyIp3SB1z
QDhaWHgFA+8lED+bWTvJxt/IMmzyYBaGnZbEjCECKZLD
-----END RSA PRIVATE KEY-----
2、生成公钥
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
如下:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6BSDlbRplhMMNZBKHX4xe8AwE
SpzHVfAcHHsX9FFSMuF91W3cxgT/g5n+qlLLFzCE3hWG/yX5NMAxR4mS3MlhyXKw
ko3tK9Ua691afod1lxORR3IaZ8nV7v5Bv8y4JDe4E3/f/bQIGzroWiJ0sXTcO41G
qvOw3G9leClSvjVnSwIDAQAB
-----END PUBLIC KEY-----
3、将RSA私钥转换成PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt > java_rsa_private_key.pem
如下:
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALoFIOVtGmWEww1k
EodfjF7wDARKnMdV8Bwcexf0UVIy4X3VbdzGBP+Dmf6qUssXMITeFYb/Jfk0wDFH
iZLcyWHJcrCSje0r1Rrr3Vp+h3WXE5FHchpnydXu/kG/zLgkN7gTf9/9tAgbOuha
InSxdNw7jUaq87Dcb2V4KVK+NWdLAgMBAAECgYBqCihhgJtOiarjBEvnrZkIOZCw
FZRfsWaJr9afph+BWw3dvH+/HYaV3YA4gwFlUlfPNgZRiTstX1u7+8q51HBa+08h
jPE8Q4GhoUY+sQ9MB8NXA6SWHNPPfMOYIeKEtKmNBdgIbtuhnob3o18rJNFIY+qC
i8djf4om93+AChmo6QJBAO31hd9qem7BnHXsxiMwS+iHlRjW9KxXva2zf+BNURSR
Z19cePReHJGE4v1C731MZlygTB5zKChQ8uZ3JLKJeX8CQQDIH4k/xbuhMb8dMdzl
AYN/CU+MgfWjlgbYjxOnTaLcbs5Mlz9v3/5I/FwqxPvzGuCjHkyh08oFfnQXvzdj
YMA1AkEApjgyOnzzZviBZXJueVgcPiKvSHmm0dg8W+Cd+72mXHqxPdCngPNYe2Ha
+VRPXDQI8LzcTwzbyUW6Vrh0/u2+2wJBAK1rZqx01VuimFLcWue4oBL+JolENXFF
GTmhAw8AIBmVjACjML3qBZmJ1vTZLtxEdlXkc9PojDCmnEPX2E+uD+ECQF2eX4EY
X95HDzQ4cm1kGQudjgfH1gZ+30DIindIHXNAOFpYeAUD7yUQP5tZO8nG38gybPJg
FoadlsSMIQIpksM=
-----END PRIVATE KEY-----
4.JAVA版本加解密:
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class RSAUtils {
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
public static final String SIGN_ALGORITHMS = "SHA256withRSA";
private static String ALGORITHM_RSA = "RSA";
/**
* 使用公钥将数据加密
* @param sourceData
* @param publicKey
* @return
*/
public static String publicEncrypt(String sourceData, String publicKey){
return rsaEncrypt(sourceData,publicKey,false);
}
/**
* 使用私钥将数据加密
* @param sourceData
* @param privateKey
* @return
*/
public static String privateEncrypt(String sourceData, String privateKey){
return rsaEncrypt(sourceData,privateKey,true);
}
/**
* 使用公钥解密
* @param encryptedData
* @param privateKey
* @return
*/
public static String publicDecrypt(String encryptedData, String privateKey) {
return rsaDecrypt(encryptedData,privateKey,false);
}
/**
* 使用私钥解密
* @param encryptedData
* @param privateKey
* @return
*/
public static String privateDecrypt(String encryptedData, String privateKey) {
return rsaDecrypt(encryptedData,privateKey,true);
}
protected static String rsaEncrypt(String sourceData, String key,boolean isPrivate){
try {
Key key1 = isPrivate ? loadPrivateKey(key) : loadPublicKey(key);
byte[] data = sourceData.getBytes();
byte[] dataReturn = new byte[0];
Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
cipher.init(Cipher.ENCRYPT_MODE, key1);
// 加密时超过117字节就报错。为此采用分段加密的办法来加密
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i,i + MAX_ENCRYPT_BLOCK));
sb.append(new String(doFinal));
dataReturn = ArrayUtils.addAll(dataReturn, doFinal);
}
return Base64.encodeBase64URLSafeString(dataReturn);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
protected static String rsaDecrypt(String encryptedData, String key,boolean isPrivate){
try {
Key key1 = isPrivate ? loadPrivateKey(key) : loadPublicKey(key);
byte[] data = Base64.decodeBase64(encryptedData);
Cipher cipher = Cipher.getInstance(ALGORITHM_RSA);
cipher.init(Cipher.DECRYPT_MODE, key1);
// 解密时超过128字节就报错。为此采用分段解密的办法来解密
byte[] dataReturn = new byte[0];
for (int i = 0; i < data.length; i += MAX_DECRYPT_BLOCK) {
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_DECRYPT_BLOCK));
dataReturn = ArrayUtils.addAll(dataReturn, doFinal);
}
return new String(dataReturn);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 私钥加签名
* @param encryptData
* @param privateKey
* @return
*/
public static String rsaSign(String encryptData, String privateKey) {
try {
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initSign(loadPrivateKey(privateKey));
signature.update(encryptData.getBytes());
byte[] signed = signature.sign();
return Base64.encodeBase64URLSafeString(signed);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 公钥验签
* @param encryptStr
* @param sign
* @param publicKey
* @return
* @throws Exception
*/
public static boolean verifySign(String encryptStr, String sign, String publicKey)throws Exception {
try {
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initVerify(loadPublicKey(publicKey));
signature.update(encryptStr.getBytes());
return signature.verify(Base64.decodeBase64(sign));
} 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 PublicKey loadPublicKey(String publicKeyStr) throws Exception {
byte[] buffer = Base64.decodeBase64(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return keyFactory.generatePublic(keySpec);
}
public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
byte[] buffer = Base64.decodeBase64(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
return keyFactory.generatePrivate(keySpec);
}
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 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6BSDlbRplhMMNZBKHX4xe8AwE" +
"SpzHVfAcHHsX9FFSMuF91W3cxgT/g5n+qlLLFzCE3hWG/yX5NMAxR4mS3MlhyXKw" +
"ko3tK9Ua691afod1lxORR3IaZ8nV7v5Bv8y4JDe4E3/f/bQIGzroWiJ0sXTcO41G" +
"qvOw3G9leClSvjVnSwIDAQAB";
String privateKeyStr = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALoFIOVtGmWEww1k" +
"EodfjF7wDARKnMdV8Bwcexf0UVIy4X3VbdzGBP+Dmf6qUssXMITeFYb/Jfk0wDFH" +
"iZLcyWHJcrCSje0r1Rrr3Vp+h3WXE5FHchpnydXu/kG/zLgkN7gTf9/9tAgbOuha" +
"InSxdNw7jUaq87Dcb2V4KVK+NWdLAgMBAAECgYBqCihhgJtOiarjBEvnrZkIOZCw" +
"FZRfsWaJr9afph+BWw3dvH+/HYaV3YA4gwFlUlfPNgZRiTstX1u7+8q51HBa+08h" +
"jPE8Q4GhoUY+sQ9MB8NXA6SWHNPPfMOYIeKEtKmNBdgIbtuhnob3o18rJNFIY+qC" +
"i8djf4om93+AChmo6QJBAO31hd9qem7BnHXsxiMwS+iHlRjW9KxXva2zf+BNURSR" +
"Z19cePReHJGE4v1C731MZlygTB5zKChQ8uZ3JLKJeX8CQQDIH4k/xbuhMb8dMdzl" +
"AYN/CU+MgfWjlgbYjxOnTaLcbs5Mlz9v3/5I/FwqxPvzGuCjHkyh08oFfnQXvzdj" +
"YMA1AkEApjgyOnzzZviBZXJueVgcPiKvSHmm0dg8W+Cd+72mXHqxPdCngPNYe2Ha" +
"+VRPXDQI8LzcTwzbyUW6Vrh0/u2+2wJBAK1rZqx01VuimFLcWue4oBL+JolENXFF" +
"GTmhAw8AIBmVjACjML3qBZmJ1vTZLtxEdlXkc9PojDCmnEPX2E+uD+ECQF2eX4EY" +
"X95HDzQ4cm1kGQudjgfH1gZ+30DIindIHXNAOFpYeAUD7yUQP5tZO8nG38gybPJg" +
"FoadlsSMIQIpksM=";
//加密
String data = "i like java";
String privateEncryptStr = RSAUtils.privateEncrypt(data, privateKeyStr);
String publicEncryptStr = RSAUtils.publicEncrypt(data, publicKeyStr);
String privateEncryptSign = RSAUtils.rsaSign(privateEncryptStr,privateKeyStr);
String publicEncryptSign = RSAUtils.rsaSign(publicEncryptStr,privateKeyStr);
System.out.println("source:" + data);
System.out.println("private encryptStr: " + privateEncryptStr);
System.out.println("public encryptStr: " + publicEncryptStr);
System.out.println("private encrypt sign: " + privateEncryptSign);
System.out.println("public encrypt sign: " + publicEncryptSign);
System.out.println("public decrypt:" + RSAUtils.publicDecrypt(privateEncryptStr, publicKeyStr));
System.out.println("private decrypt:" + RSAUtils.privateDecrypt(publicEncryptStr, privateKeyStr));
System.out.println("verifySign1: " + RSAUtils.verifySign(privateEncryptStr,privateEncryptSign,publicKeyStr));
System.out.println("verifySign2: " + RSAUtils.verifySign(publicEncryptStr,publicEncryptSign,publicKeyStr));
System.out.println("\r\n");
publicEncryptStr = "WopnO2LnolZ7XpOwA_ktOhfkkaQQJQgkJudk3ZH_-ob36GQFv968nE1UBXxNekA9pIHBcvcl0ZWfwFhk-kyOF2FmQvpPY9LkqiCV0T32vhJet0n93ti2PBoFILxvChjzdOgSG9M0flH78Vm696Q4mHo7VMt_XMoHDTd3Rbagvt8";
privateEncryptStr = "Fwb5BtLRveCWbx7FkXarl1zVOdwDvbDTl7gv-vPHXpj-T2wm9GlUDn3X0wnHHXkE8cqAT6PcE0g0ide6beP9_ysHMLgnC6wVqkomIKsi6C9TcGd4d6XQBjeJgdgccvDcD-7pcKrV9W-_Z7jkYkwwrjPGPd_uckEHR_cDXyOX4PU";
System.out.println("php >>>> private decrypt: " + RSAUtils.privateDecrypt(publicEncryptStr, privateKeyStr));
System.out.println("php >>>> public decrypt: " + RSAUtils.publicDecrypt(privateEncryptStr, publicKeyStr));
publicEncryptStr = "T2LFtY3dF_b6OBO07BN-3LtMSEBZqDukovDZ4HGCff8wosvlowf6IFJ3U7LFBIeHfiHBKiFuAV8-pFltCfTXtA4AwgVUnwbBMBWBfIJiLDi02ev30V-5BcYEuSF-cEdnSUd7WecrX4rHhzYLueGuj8H6c7RRbSbrJ6_3EFfU-K0";
System.out.println("js >>>> private decrypt: " + RSAUtils.privateDecrypt(publicEncryptStr, privateKeyStr));
}
}
输出如下:
source: i like java
private encryptStr: fHG5JMpTTF-KzrPCp827opRy3BvqmVIpIZS4gVuWqY5NeLsgoLxdrq3SaxUp_oBQ9pVqNlEiU9SIwbqJDjIqjHsCtVMOLoEdWicib_wCaoB16veKTEC4GnvviJwlS5IedH27oWGHKTTc6Ii5cLiQncjDAadvm0KCdC74yrwPqnc
public encryptStr: raoQQsfN0KBfPAMRWnxr9kFPvJ6BgQ7PRBCMnz0nWsH03sD4IdlMvKpj78BHe7V7Ga1HZHyDxuJhVaJ0T5qKl8qHXzvKquzNtdMru7G4X9o8ylzkGxJLg-HYCWOrsZ77ZMaKoV9p-TCf-yMI21OpL_5JGot-XNfVVPkmg0z9FW0
private encrypt sign: jlJvXY5t8KesDi3WaPr71jj2BigHLDr3b827Jl9xspbecdUjPB44Xe3sjWnzvFDLpKJGiNTvqE-Qyu3FZpG_NyI5yhVrAQgZmyYfVywmeDDsTOQYk1xP0UEfFgB0MXsFdlfSdMu5JcR5kgC5Xl5jds1b0Z2Nq7gQ-bvFJQcuHgU
public encrypt sign: ngN2kQppfITyn5yAfNc1c-ofK20trKJWXIjlaJhWtm7s2jzv5rcsPY5JH06CMAIIbnKGIUcoVvMeKavAIVFb4G_h3CvXIYnxMjQL19Op-SbtyGNwT-rZzTEP8tKfxFRVm7SrHHDz2s287S3vqQz9vGEGNmgDHEdrCfHBmmoFkQA
public decrypt: i like java
private decrypt: i like java
verifySign1: true
verifySign2: true
php >>>> private decrypt: i like php
php >>>> public decrypt: i like php
js >>>> private decrypt: i like JS
5.PHP版本加解密
<?php
$private_key = <<<KEY
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC6BSDlbRplhMMNZBKHX4xe8AwESpzHVfAcHHsX9FFSMuF91W3c
xgT/g5n+qlLLFzCE3hWG/yX5NMAxR4mS3MlhyXKwko3tK9Ua691afod1lxORR3Ia
Z8nV7v5Bv8y4JDe4E3/f/bQIGzroWiJ0sXTcO41GqvOw3G9leClSvjVnSwIDAQAB
AoGAagooYYCbTomq4wRL562ZCDmQsBWUX7Fmia/Wn6YfgVsN3bx/vx2Gld2AOIMB
ZVJXzzYGUYk7LV9bu/vKudRwWvtPIYzxPEOBoaFGPrEPTAfDVwOklhzTz3zDmCHi
hLSpjQXYCG7boZ6G96NfKyTRSGPqgovHY3+KJvd/gAoZqOkCQQDt9YXfanpuwZx1
7MYjMEvoh5UY1vSsV72ts3/gTVEUkWdfXHj0XhyRhOL9Qu99TGZcoEwecygoUPLm
dySyiXl/AkEAyB+JP8W7oTG/HTHc5QGDfwlPjIH1o5YG2I8Tp02i3G7OTJc/b9/+
SPxcKsT78xrgox5ModPKBX50F783Y2DANQJBAKY4Mjp882b4gWVybnlYHD4ir0h5
ptHYPFvgnfu9plx6sT3Qp4DzWHth2vlUT1w0CPC83E8M28lFula4dP7tvtsCQQCt
a2asdNVbophS3FrnuKAS/iaJRDVxRRk5oQMPACAZlYwAozC96gWZidb02S7cRHZV
5HPT6IwwppxD19hPrg/hAkBdnl+BGF/eRw80OHJtZBkLnY4Hx9YGft9AyIp3SB1z
QDhaWHgFA+8lED+bWTvJxt/IMmzyYBaGnZbEjCECKZLD
-----END RSA PRIVATE KEY-----
KEY;
$private8_key = <<<KEY
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALoFIOVtGmWEww1k
EodfjF7wDARKnMdV8Bwcexf0UVIy4X3VbdzGBP+Dmf6qUssXMITeFYb/Jfk0wDFH
iZLcyWHJcrCSje0r1Rrr3Vp+h3WXE5FHchpnydXu/kG/zLgkN7gTf9/9tAgbOuha
InSxdNw7jUaq87Dcb2V4KVK+NWdLAgMBAAECgYBqCihhgJtOiarjBEvnrZkIOZCw
FZRfsWaJr9afph+BWw3dvH+/HYaV3YA4gwFlUlfPNgZRiTstX1u7+8q51HBa+08h
jPE8Q4GhoUY+sQ9MB8NXA6SWHNPPfMOYIeKEtKmNBdgIbtuhnob3o18rJNFIY+qC
i8djf4om93+AChmo6QJBAO31hd9qem7BnHXsxiMwS+iHlRjW9KxXva2zf+BNURSR
Z19cePReHJGE4v1C731MZlygTB5zKChQ8uZ3JLKJeX8CQQDIH4k/xbuhMb8dMdzl
AYN/CU+MgfWjlgbYjxOnTaLcbs5Mlz9v3/5I/FwqxPvzGuCjHkyh08oFfnQXvzdj
YMA1AkEApjgyOnzzZviBZXJueVgcPiKvSHmm0dg8W+Cd+72mXHqxPdCngPNYe2Ha
+VRPXDQI8LzcTwzbyUW6Vrh0/u2+2wJBAK1rZqx01VuimFLcWue4oBL+JolENXFF
GTmhAw8AIBmVjACjML3qBZmJ1vTZLtxEdlXkc9PojDCmnEPX2E+uD+ECQF2eX4EY
X95HDzQ4cm1kGQudjgfH1gZ+30DIindIHXNAOFpYeAUD7yUQP5tZO8nG38gybPJg
FoadlsSMIQIpksM=
-----END PRIVATE KEY-----
KEY;
$public_key = <<<KEY
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6BSDlbRplhMMNZBKHX4xe8AwE
SpzHVfAcHHsX9FFSMuF91W3cxgT/g5n+qlLLFzCE3hWG/yX5NMAxR4mS3MlhyXKw
ko3tK9Ua691afod1lxORR3IaZ8nV7v5Bv8y4JDe4E3/f/bQIGzroWiJ0sXTcO41G
qvOw3G9leClSvjVnSwIDAQAB
-----END PUBLIC KEY-----
KEY;
$data = 'i like php';
//使用公钥将数据加密
$encrypt_data = RsaUtils::publicEncrypt($data,$public_key);
//使用私钥将数据解密
$decrypt_data = RsaUtils::privateDecrypt($encrypt_data,$private_key);
echo 'public encrypt data:'.$encrypt_data.PHP_EOL;
echo 'private decrypt data:'.$decrypt_data.PHP_EOL;
//使用私钥将数据加密
$encrypt_data = RsaUtils::privateEncrypt($data,$private_key);
//使用私钥将加密数据加签
$private_encrypt_sign = RsaUtils::rsaSign($encrypt_data,$private_key);
//使用公钥解签
$public_check_sign = RsaUtils::verifySign($encrypt_data,$private_encrypt_sign,$public_key);
//使用公钥将数据解密
$decrypt_data = RsaUtils::publicDecrypt($encrypt_data,$public_key);
echo 'private encrypt data: '.$encrypt_data.PHP_EOL;
echo 'private encrypt sign: '.$private_encrypt_sign.PHP_EOL;
echo 'public check sign: '.$public_check_sign.PHP_EOL;
echo 'public decrypt data: '.$decrypt_data.PHP_EOL;
//验证java加密解密方法
$private_encrypt_data = 'fHG5JMpTTF-KzrPCp827opRy3BvqmVIpIZS4gVuWqY5NeLsgoLxdrq3SaxUp_oBQ9pVqNlEiU9SIwbqJDjIqjHsCtVMOLoEdWicib_wCaoB16veKTEC4GnvviJwlS5IedH27oWGHKTTc6Ii5cLiQncjDAadvm0KCdC74yrwPqnc';
$public_decrypt_data = RsaUtils::publicDecrypt($private_encrypt_data,$public_key);
$sign_data1 = 'jlJvXY5t8KesDi3WaPr71jj2BigHLDr3b827Jl9xspbecdUjPB44Xe3sjWnzvFDLpKJGiNTvqE-Qyu3FZpG_NyI5yhVrAQgZmyYfVywmeDDsTOQYk1xP0UEfFgB0MXsFdlfSdMu5JcR5kgC5Xl5jds1b0Z2Nq7gQ-bvFJQcuHgU';
$verify_sign1 = RsaUtils::verifySign($private_encrypt_data,$sign_data1,$public_key);
$public_encrypt_data = 'raoQQsfN0KBfPAMRWnxr9kFPvJ6BgQ7PRBCMnz0nWsH03sD4IdlMvKpj78BHe7V7Ga1HZHyDxuJhVaJ0T5qKl8qHXzvKquzNtdMru7G4X9o8ylzkGxJLg-HYCWOrsZ77ZMaKoV9p-TCf-yMI21OpL_5JGot-XNfVVPkmg0z9FW0';
$private_decrypt_data = RsaUtils::privateDecrypt($public_encrypt_data, $private_key);
$sign_data2 = 'ngN2kQppfITyn5yAfNc1c-ofK20trKJWXIjlaJhWtm7s2jzv5rcsPY5JH06CMAIIbnKGIUcoVvMeKavAIVFb4G_h3CvXIYnxMjQL19Op-SbtyGNwT-rZzTEP8tKfxFRVm7SrHHDz2s287S3vqQz9vGEGNmgDHEdrCfHBmmoFkQA';
$verify_sign2 = RsaUtils::verifySign($public_encrypt_data,$sign_data2,$public_key);
echo PHP_EOL;
echo 'public_decrypt_data: '.$public_decrypt_data.PHP_EOL;
echo 'verifySign1: '. $verify_sign1.PHP_EOL;
echo 'private_decrypt_data: '.$private_decrypt_data.PHP_EOL;
echo 'verifySign2: '. $verify_sign2.PHP_EOL;
$public_encrypt_data = 'T2LFtY3dF_b6OBO07BN-3LtMSEBZqDukovDZ4HGCff8wosvlowf6IFJ3U7LFBIeHfiHBKiFuAV8-pFltCfTXtA4AwgVUnwbBMBWBfIJiLDi02ev30V-5BcYEuSF-cEdnSUd7WecrX4rHhzYLueGuj8H6c7RRbSbrJ6_3EFfU-K0';
$private_decrypt_data = RsaUtils::privateDecrypt($public_encrypt_data,$private_key);
echo PHP_EOL;
echo 'private_decrypt_data: '.$private_decrypt_data.PHP_EOL;
class RsaUtils{
/**
* 签名算法,SHA256WithRSA
*/
private const SIGNATURE_ALGORITHM = OPENSSL_ALGO_SHA256;
/**
* RSA最大加密明文大小
*/
private const MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private const MAX_DECRYPT_BLOCK = 128;
/**
* 使用公钥将数据加密
* @param $data string 需要加密的数据
* @param $publicKey string 公钥
* @return string 返回加密串(base64编码)
*/
public static function publicEncrypt($data,$publicKey){
$data = str_split($data, self::MAX_ENCRYPT_BLOCK);
$encrypted = '';
foreach($data as & $chunk){
if(!openssl_public_encrypt($chunk, $encryptData, $publicKey)){
return '';
}else{
$encrypted .= $encryptData;
}
}
return self::urlSafeBase64encode($encrypted);
}
/**
* 使用私钥解密
* @param $data string 需要解密的数据
* @param $privateKey string 私钥
* @return string 返回解密串
*/
public static function privateDecrypt($data,$privateKey){
$data = str_split(self::urlSafeBase64decode($data), self::MAX_DECRYPT_BLOCK);
$decrypted = '';
foreach($data as & $chunk){
if(!openssl_private_decrypt($chunk, $decryptData, $privateKey)){
return '';
}else{
$decrypted .= $decryptData;
}
}
return $decrypted;
}
/**
* 使用私钥将数据加密
* @param $data string 需要加密的数据
* @param $privateKey string 私钥
* @return string 返回加密串(base64编码)
*/
public static function privateEncrypt($data,$privateKey){
$data = str_split($data, self::MAX_ENCRYPT_BLOCK);
$encrypted = '';
foreach($data as & $chunk){
if(!openssl_private_encrypt($chunk, $encryptData, $privateKey)){
return '';
}else{
$encrypted .= $encryptData;
}
}
return self::urlSafeBase64encode($encrypted);
}
/**
* 使用公钥解密
* @param $data string 需要解密的数据
* @param $publicKey string 公钥
* @return string 返回解密串
*/
public static function publicDecrypt($data,$publicKey){
$data = str_split(self::urlSafeBase64decode($data), self::MAX_DECRYPT_BLOCK);
$decrypted = '';
foreach($data as & $chunk){
if(!openssl_public_decrypt($chunk, $decryptData, $publicKey)){
return '';
}else{
$decrypted .= $decryptData;
}
}
return $decrypted;
}
/**
* 私钥加签名
* @param $data 被加签数据
* @param $privateKey 私钥
* @return mixed|string
*/
public static function rsaSign($data, $privateKey){
if(openssl_sign($data, $sign, $privateKey, self::SIGNATURE_ALGORITHM)){
return self::urlSafeBase64encode($sign);
}
return '';
}
/**
* 公钥验签
* @param $data 被加签数据
* @param $sign 签名
* @param $publicKey 公钥
* @return bool
*/
public static function verifySign($data, $sign, $publicKey):bool {
return (1 == openssl_verify($data, self::urlSafeBase64decode($sign), $publicKey, self::SIGNATURE_ALGORITHM));
}
/**
* url base64编码
* @param $string
* @return mixed|string
*/
public static function urlSafeBase64encode($string){
$data = str_replace(array('+','/','='), array( '-','_',''), base64_encode($string));
return $data;
}
/**
* url base64解码
* @param $string
* @return bool|string
*/
public static function urlSafeBase64decode($string){
$data = str_replace(array('-','_'), array('+','/'), $string);
$mod4 = strlen($data) % 4;
if($mod4){
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
}
输出如下:
public encrypt data: WopnO2LnolZ7XpOwA_ktOhfkkaQQJQgkJudk3ZH_-ob36GQFv968nE1UBXxNekA9pIHBcvcl0ZWfwFhk-kyOF2FmQvpPY9LkqiCV0T32vhJet0n93ti2PBoFILxvChjzdOgSG9M0flH78Vm696Q4mHo7VMt_XMoHDTd3Rbagvt8
private decrypt data: i like php
public encrypt data: Fwb5BtLRveCWbx7FkXarl1zVOdwDvbDTl7gv-vPHXpj-T2wm9GlUDn3X0wnHHXkE8cqAT6PcE0g0ide6beP9_ysHMLgnC6wVqkomIKsi6C9TcGd4d6XQBjeJgdgccvDcD-7pcKrV9W-_Z7jkYkwwrjPGPd_uckEHR_cDXyOX4PU
private rsa sign: T-I3KLkBEMRi9YdflyjNZxh_IhEC2mG4vFaq5FeFzs03l7ojtmf3pXFOwjz6qbHUwIJ-tjIMVammfCrYKa0AjMAX_L7-99_EUPmMvmjXS_8z0aZuY5dZPgRCBxklKem56r0qss-iSGTGsh3eivhUiHvtRTBXhtbkpjjlkkqXy-k
public check sign: 1
private decrypt data: i like php
public_decrypt_data: i like java
verifySign1: 1
private_decrypt_data: i like java
verifySign2: 1
private_decrypt_data: i like JS
6.JS版本加解密
var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var b64pad = "=";
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
//整型转字符串
function int2char(n) {
return BI_RM.charAt(n);
}
//十六进制转Base64字符串
function hex2b64(h) {
var i;
var c;
var ret = "";
for (i = 0; i + 3 <= h.length; i += 3) {
c = parseInt(h.substring(i, i + 3), 16);
ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
}
if (i + 1 == h.length) {
c = parseInt(h.substring(i, i + 1), 16);
ret += b64map.charAt(c << 2);
}
else if (i + 2 == h.length) {
c = parseInt(h.substring(i, i + 2), 16);
ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
}
while ((ret.length & 3) > 0) {
ret += b64pad;
}
return ret;
}
//Base64字符串转十六进制
function b64tohex(s) {
var ret = "";
var i;
var k = 0; // b64 state, 0-3
var slop = 0;
for (i = 0; i < s.length; ++i) {
if (s.charAt(i) == b64pad) {
break;
}
var v = b64map.indexOf(s.charAt(i));
if (v < 0) {
continue;
}
if (k == 0) {
ret += int2char(v >> 2);
slop = v & 3;
k = 1;
}
else if (k == 1) {
ret += int2char((slop << 2) | (v >> 4));
slop = v & 0xf;
k = 2;
}
else if (k == 2) {
ret += int2char(slop);
ret += int2char(v >> 2);
slop = v & 3;
k = 3;
}
else {
ret += int2char((slop << 2) | (v >> 4));
ret += int2char(v & 0xf);
k = 0;
}
}
if (k == 1) {
ret += int2char(slop << 2);
}
return ret;
}
//十六进制转字节
function hexToBytes(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
//字节转十六进制
function bytesToHex(bytes) {
for (var hex = [], i = 0; i < bytes.length; i++) {
hex.push((bytes[i] >>> 4).toString(16));
hex.push((bytes[i] & 0xF).toString(16));
}
return hex.join("");
}
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;
}
//长字符串加密
JSEncrypt.prototype.encryptLong = function (string) {
var k = this.getKey();
//var MAX_ENCRYPT_BLOCK = (((k.n.bitLength() + 7) >> 3) - 11);
var MAX_ENCRYPT_BLOCK = 117;
try {
var lt = "";
var ct = "";
//RSA每次加密117bytes,需要辅助方法判断字符串截取位置
//1.获取字符串截取点
var bytes = new Array();
bytes.push(0);
var byteNo = 0;
var len, c;
len = string.length;
var temp = 0;
for (var i = 0; i < len; i++) {
c = string.charCodeAt(i);
if (c >= 0x010000 && c <= 0x10FFFF) {
byteNo += 4;
} else if (c >= 0x000800 && c <= 0x00FFFF) {
byteNo += 3;
} else if (c >= 0x000080 && c <= 0x0007FF) {
byteNo += 2;
} else {
byteNo += 1;
}
if ((byteNo % MAX_ENCRYPT_BLOCK) >= 114 || (byteNo % MAX_ENCRYPT_BLOCK) == 0) {
if (byteNo - temp >= 114) {
bytes.push(i);
temp = byteNo;
}
}
}
//2.截取字符串并分段加密
if (bytes.length > 1) {
for (var i = 0; i < bytes.length - 1; i++) {
var str;
if (i == 0) {
str = string.substring(0, bytes[i + 1] + 1);
} else {
str = string.substring(bytes[i] + 1, bytes[i + 1] + 1);
}
var t1 = k.encrypt(str);
ct += t1;
}
;
if (bytes[bytes.length - 1] != string.length - 1) {
var lastStr = string.substring(bytes[bytes.length - 1] + 1);
ct += k.encrypt(lastStr);
}
return hex2b64(ct);
}
var t = k.encrypt(string);
var y = hex2b64(t);
return y;
} catch (ex) {
return false;
}
};
//长字符串解密
JSEncrypt.prototype.decryptLong = function (string) {
var k = this.getKey();
// var MAX_DECRYPT_BLOCK = ((k.n.bitLength()+7)>>3);
var MAX_DECRYPT_BLOCK = 128;
try {
var ct = "";
var t1;
var bufTmp;
var hexTmp;
var str = b64tohex(string);
var buf = hexToBytes(str);
var inputLen = buf.length;
//开始长度
var offSet = 0;
//结束长度
var endOffSet = MAX_DECRYPT_BLOCK;
//分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
bufTmp = buf.slice(offSet, endOffSet);
hexTmp = bytesToHex(bufTmp);
t1 = k.decrypt(hexTmp);
ct += t1;
} else {
bufTmp = buf.slice(offSet, inputLen);
hexTmp = bytesToHex(bufTmp);
t1 = k.decrypt(hexTmp);
ct += t1;
}
offSet += MAX_DECRYPT_BLOCK;
endOffSet += MAX_DECRYPT_BLOCK;
}
return ct;
} catch (ex) {
return false;
}
};
// Call this code when the page is done loading.
var publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6BSDlbRplhMMNZBKHX4xe8AwE" +
"SpzHVfAcHHsX9FFSMuF91W3cxgT/g5n+qlLLFzCE3hWG/yX5NMAxR4mS3MlhyXKw" +
"ko3tK9Ua691afod1lxORR3IaZ8nV7v5Bv8y4JDe4E3/f/bQIGzroWiJ0sXTcO41G" +
"qvOw3G9leClSvjVnSwIDAQAB";
var privateKeyStr = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALoFIOVtGmWEww1k" +
"EodfjF7wDARKnMdV8Bwcexf0UVIy4X3VbdzGBP+Dmf6qUssXMITeFYb/Jfk0wDFH" +
"iZLcyWHJcrCSje0r1Rrr3Vp+h3WXE5FHchpnydXu/kG/zLgkN7gTf9/9tAgbOuha" +
"InSxdNw7jUaq87Dcb2V4KVK+NWdLAgMBAAECgYBqCihhgJtOiarjBEvnrZkIOZCw" +
"FZRfsWaJr9afph+BWw3dvH+/HYaV3YA4gwFlUlfPNgZRiTstX1u7+8q51HBa+08h" +
"jPE8Q4GhoUY+sQ9MB8NXA6SWHNPPfMOYIeKEtKmNBdgIbtuhnob3o18rJNFIY+qC" +
"i8djf4om93+AChmo6QJBAO31hd9qem7BnHXsxiMwS+iHlRjW9KxXva2zf+BNURSR" +
"Z19cePReHJGE4v1C731MZlygTB5zKChQ8uZ3JLKJeX8CQQDIH4k/xbuhMb8dMdzl" +
"AYN/CU+MgfWjlgbYjxOnTaLcbs5Mlz9v3/5I/FwqxPvzGuCjHkyh08oFfnQXvzdj" +
"YMA1AkEApjgyOnzzZviBZXJueVgcPiKvSHmm0dg8W+Cd+72mXHqxPdCngPNYe2Ha" +
"+VRPXDQI8LzcTwzbyUW6Vrh0/u2+2wJBAK1rZqx01VuimFLcWue4oBL+JolENXFF" +
"GTmhAw8AIBmVjACjML3qBZmJ1vTZLtxEdlXkc9PojDCmnEPX2E+uD+ECQF2eX4EY" +
"X95HDzQ4cm1kGQudjgfH1gZ+30DIindIHXNAOFpYeAUD7yUQP5tZO8nG38gybPJg" +
"FoadlsSMIQIpksM=";
var sourceStr = "i like JS";
//公钥加密
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKeyStr);
var encrypted = encrypt.encryptLong(sourceStr);
encrypted = urlsafeEncode(encrypted);
//私钥解密
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(privateKeyStr);
var uncrypted = decrypt.decryptLong(urlsafeDecode(encrypted));
console.log("public encrypted: ",encrypted);
console.log("private uncrypted: ",uncrypted);
console.log("private uncrypted: ",decrypt.decryptLong(urlsafeDecode("WopnO2LnolZ7XpOwA_ktOhfkkaQQJQgkJudk3ZH_-ob36GQFv968nE1UBXxNekA9pIHBcvcl0ZWfwFhk-kyOF2FmQvpPY9LkqiCV0T32vhJet0n93ti2PBoFILxvChjzdOgSG9M0flH78Vm696Q4mHo7VMt_XMoHDTd3Rbagvt8")));
console.log("private uncrypted: ",decrypt.decryptLong(urlsafeDecode("raoQQsfN0KBfPAMRWnxr9kFPvJ6BgQ7PRBCMnz0nWsH03sD4IdlMvKpj78BHe7V7Ga1HZHyDxuJhVaJ0T5qKl8qHXzvKquzNtdMru7G4X9o8ylzkGxJLg-HYCWOrsZ77ZMaKoV9p-TCf-yMI21OpL_5JGot-XNfVVPkmg0z9FW0")));