在系統與系統的數據交互中,有些敏感數據是不能直接明文傳輸的,因此在發送數據以前要進行加密,在接收到數據時進行解密處理;然而因爲系統與系統之間的開發語言不一樣。本次需求是生成二維碼是經過java生成,由php來解密。基於這類需求因此選擇了RSA進行加解密。 1、生成RSA公私鑰
分紅三步生成RSA公私鑰,第一、2步能夠知足php的使用,因爲java的私鑰要轉化爲PKCS8格式才能使用,因此執行第三步來實現
一、生成私鑰javascript
openssl genrsa -out rsa_private_key.pem 1024
以下:php
-----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-----
二、生成公鑰html
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-----
三、將RSA私鑰轉換成PKCS8格式java
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-----
2、PHP實現RSA的加密解密。git
<?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; } } ?>
3、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))); }
4、javascript rsa加解密shell
<!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>
附 js_rsa加解密DEMOapache
驗證:經過java生成的密文:
doKFqNWXi6oEoURhYboPgEGsuQ34f8sYR3QmrePdPhE5x6GgemYjGM3iTiwhDtBuIc4_caZ2nGm0qJ82NLwQQdS4eaXr-ioKpfR_F06CmE2TU69FFjwuPwwlk6xdOfYPJan8rqQGcVdmqa0Ig04dA-M1Dkif8WAZ6mYUKb30aLA數組
再經過php進行解密app