系统与系统的数据交互中,有些敏感数据是不能直接明文传输的,所以在发送数据之前要进行加密,在接收到数据时进行解密处理;然而由于系统与系统之间的开发语言不同。
本次需求是生成二维码是通过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("( | | | )",""); } 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(" "); 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")));
引入 <script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>