java 使用jsencrypt的js的rsa庫實現rsa加密傳輸,防止http明文傳輸
阿新 • • 發佈:2018-11-11
JSEncrypt 是js實現的rsa加密庫
前端使用rsa公鑰加密登入資訊,傳輸加密結果給服務端,服務端接收後使用私鑰解密,實現安全資訊傳輸
【注】:JSEncrypt支援的是openssl生成的pkcs1格式私鑰,java需要pkcs8格式私鑰,公鑰格式不變
//公私鑰生成 , 【私鑰】格式轉換 //生成公私鑰 openssl genrsa -out rsa_1024_priv.pem 1024 && openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem //或者http://travistidwell.com/jsencrypt/demo/index.html 線上生成 //上面生成的是pkcs1,java需要pkcs8,私鑰要轉為pkcs8格式 //pkcs1 轉pkcs8 openssl pkcs8 -topk8 -inform PEM -in private.key -outform pem -nocrypt -out pkcs8.pem //pkcs8 轉pkcs1 openssl rsa -in pkcs8.pem -out pri_key.pem
maven專案
//pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.dddd</groupId> <artifactId>jrsa</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.11</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency> </dependencies> </project>
//RSAUtils.java import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.*; import java.util.HashMap; import java.util.Map; public class RSAUtils { public static final String CHARSET = "UTF-8"; public static final String RSA_ALGORITHM = "RSA"; public static Map<String, String> createKeys(int keySize){ //為RSA演算法建立一個KeyPairGenerator物件 KeyPairGenerator kpg; try{ kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM); }catch(NoSuchAlgorithmException e){ throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]"); } //初始化KeyPairGenerator物件,金鑰長度 kpg.initialize(keySize); //生成密匙對 KeyPair keyPair = kpg.generateKeyPair(); //得到公鑰 Key publicKey = keyPair.getPublic(); String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded()); //得到私鑰 Key privateKey = keyPair.getPrivate(); System.out.println("私鑰格式:"+privateKey.getFormat()); String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded()); Map<String, String> keyPairMap = new HashMap<String, String>(); keyPairMap.put("publicKey", publicKeyStr); keyPairMap.put("privateKey", privateKeyStr); return keyPairMap; } /** * 得到公鑰 * @param publicKey 金鑰字串(經過base64編碼) * @throws Exception */ public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException { //通過X509編碼的Key指令獲得公鑰物件 KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey)); RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec); return key; } /** * 得到私鑰 * @param privateKey 金鑰字串(經過base64編碼) * @throws Exception */ public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException { //通過PKCS#8編碼的Key指令獲得私鑰物件 KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec); return key; } /** * 公鑰加密 * @param data * @param publicKey * @return */ public static String publicEncrypt(String data, RSAPublicKey publicKey){ try{ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength())); }catch(Exception e){ throw new RuntimeException("加密字串[" + data + "]時遇到異常", e); } } /** * 私鑰解密 * @param data * @param privateKey * @return */ public static String privateDecrypt(String data, RSAPrivateKey privateKey){ try{ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, privateKey); return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET); }catch(Exception e){ throw new RuntimeException("解密字串[" + data + "]時遇到異常", e); } } /** * 私鑰加密 * @param data * @param privateKey * @return */ public static String privateEncrypt(String data, RSAPrivateKey privateKey){ try{ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength())); }catch(Exception e){ throw new RuntimeException("加密字串[" + data + "]時遇到異常", e); } } /** * 公鑰解密 * @param data * @param publicKey * @return */ public static String publicDecrypt(String data, RSAPublicKey publicKey){ try{ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, publicKey); return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET); }catch(Exception e){ throw new RuntimeException("解密字串[" + data + "]時遇到異常", e); } } private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){ int maxBlock = 0; if(opmode == Cipher.DECRYPT_MODE){ maxBlock = keySize / 8; }else{ maxBlock = keySize / 8 - 11; } ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] buff; int i = 0; try{ while(datas.length > offSet){ if(datas.length-offSet > maxBlock){ buff = cipher.doFinal(datas, offSet, maxBlock); }else{ buff = cipher.doFinal(datas, offSet, datas.length-offSet); } out.write(buff, 0, buff.length); i++; offSet = i * maxBlock; } }catch(Exception e){ throw new RuntimeException("加解密閥值為["+maxBlock+"]的資料時發生異常", e); } byte[] resultDatas = out.toByteArray(); IOUtils.closeQuietly(out); return resultDatas; } }
//Test2.java
/**
* 前後端rsa資料傳輸
*/
public class Test2 {
public static void main(String[] args) throws Exception{
//生成公私鑰 openssl genrsa -out rsa_1024_priv.pem 1024&& openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem
//或者http://travistidwell.com/jsencrypt/demo/index.html 線上生成
//上面生成的是pkcs1,java需要pkcs8,私鑰要轉為pkcs8格式
//pkcs1 轉pkcs8 openssl pkcs8 -topk8 -inform PEM -in private.key -outform pem -nocrypt -out pkcs8.pem
//pkcs8 轉pkcs1 openssl rsa -in pkcs8.pem -out pri_key.pem
String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCLh48Wq5I6atYb0kurC09Q535\n" +
"b37dZpJR+UElX5cEfNMiVQwcK3IU/74lwWC6hCC90iFPjIcK+p/+XA2FBSQDgcW1\n" +
"24rh+KTMOgesxLyYrjnrfPyUUuBm3MUQnTAytV6IAVMvq7s0N+R/zXKxpYBypMgD\n" +
"l5XYbOvUE5SJwTvhIQIDAQAB".replace("\n","");
String privateKey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMKz0Z18guQrLPdC\n" +
"JdtPK0vR7SpeBie0LBELf7atQYyKJ3WgX6CNGmrFDlsQWp17X0T/s9KzaHbpc2I2\n" +
"PvlZoBz7CHnfDGwi7p/sI9dVNeOdfFa5drsqmK60rGrj6BzveGgPDJJoXPb5Lbfb\n" +
"MDN34hG/QGfuDsEkfUbYYB+apC0ZAgMBAAECgYEAuFiPWGBCggyLJ5T+yPXdlY0u\n" +
"05VwmHkT3BOaGXlTfeB02f89a4MOBxeKrxf94+ui2W6NcSqi9yu0LsITv/1nBUK4\n" +
"oBOjC75garFjYjSDTdGLD96BDOahVzqKMY8eE9XEZQEX4bhj6ZDa5q8nvGnkant0\n" +
"o5yZzGeT2ZMK69SMdjECQQDfR2TBcNHhJLp3I8qzuV8iYsZnyUEU+I47DRRv9qKl\n" +
"1WWAW3EJ7cyv69OkAQHwJy2BDQDuSFgn6T/lx4N1yCmlAkEA3zxXROmK5T7shE1H\n" +
"Ymt3AdTSFnAcR/lKbd/+iuIhaN77MOzEaKvlDxRv5Jh4G+lLkwHFSAaRYRPmkv6q\n" +
"mBqTZQJBAN3uA6r2rdaggCrty4wqg/IUxerhMqxahl0Rmi/TsUUuQA5+VXQuBpcR\n" +
"y7KnQbrn5iXwu+0cwWsiP93wGq3Wv/UCQCvw0Ky7258sN5oDLB3vUUmG/qN0Bd0U\n" +
"8NWX1Z64zCK8YW1L7Y086KWDPFMev+WekkWpf4+h21PkeupMPoAaGxECQGDnx0/U\n" +
"A972Y4wZfP+jjCG74UdqSH51+FRrLOzLUuhvQSiKYmSpZXpWzOKa0ZnmAuIfjWIe\n" +
"n/VmjuQ6iaLiWR0=".replace("\n","");
String encodedData = "jJlRUw9JXFtLvO3dLOTQlFu9oHVnJsfi0sZ0u9BbEZMj8IlsPvSA95eExRCpe060VFaCEc7j17tm4Qpw2kX0dDg71DoPPYioT06Nhwf2BkNghtKkcWhDr8HJo85aIN2MAWSk4B/kpsvaUDuazJV7QyKaMK80UtQ/ZhzGvkR0AnI=";
String decodedData = RSAUtils.privateDecrypt(encodedData, RSAUtils.getPrivateKey(privateKey));
System.out.println("解密後文字: \r\n" + decodedData);
}
}
以下是前端單html頁面, 需要單獨下載 jquery 與 JSEncrypt 庫
//test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="jquery.min.js"></script>
<script src="jsencrypt.min.js"></script>
<script type="text/javascript">
// Call this code when the page is done loading.
$(function() {
// Run a quick encryption/decryption when they click.
$('#testme').click(function() {
// Encrypt with the public key...
var encrypt = new JSEncrypt();
encrypt.setPublicKey($('#pubkey').val());
var encrypted = encrypt.encrypt($('#input').val());
$('#output').val(encrypted);
// Decrypt with the private key...
var decrypt = new JSEncrypt();
decrypt.setPrivateKey($('#privkey').val());
var uncrypted = decrypt.decrypt(encrypted);
// Now a simple check to see if the round-trip worked.
if (uncrypted == $('#input').val()) {
alert('It works!!!');
}
else {
alert('Something went wrong....');
}
});
});
</script>
</head>
<body>
<label for="privkey">Private Key</label><br/>
<textarea id="privkey" rows="15" cols="65">-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDlOJu6TyygqxfWT7eLtGDwajtNFOb9I5XRb6khyfD1Yt3YiCgQ
WMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76xFxdU6jE0NQ+Z+zEdhUTooNR
aY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4gwQco1KRMDSmXSMkDwIDAQAB
AoGAfY9LpnuWK5Bs50UVep5c93SJdUi82u7yMx4iHFMc/Z2hfenfYEzu+57fI4fv
xTQ//5DbzRR/XKb8ulNv6+CHyPF31xk7YOBfkGI8qjLoq06V+FyBfDSwL8KbLyeH
m7KUZnLNQbk8yGLzB3iYKkRHlmUanQGaNMIJziWOkN+N9dECQQD0ONYRNZeuM8zd
8XJTSdcIX4a3gy3GGCJxOzv16XHxD03GW6UNLmfPwenKu+cdrQeaqEixrCejXdAF
z/7+BSMpAkEA8EaSOeP5Xr3ZrbiKzi6TGMwHMvC7HdJxaBJbVRfApFrE0/mPwmP5
rN7QwjrMY+0+AbXcm8mRQyQ1+IGEembsdwJBAN6az8Rv7QnD/YBvi52POIlRSSIM
V7SwWvSK4WSMnGb1ZBbhgdg57DXaspcwHsFV7hByQ5BvMtIduHcT14ECfcECQATe
aTgjFnqE/lQ22Rk0eGaYO80cc643BXVGafNfd9fcvwBMnk0iGX0XRsOozVt5Azil
psLBYuApa66NcVHJpCECQQDTjI2AQhFc1yRnCU/YgDnSpJVm1nASoRUnU8Jfm3Oz
uku7JUXcVpt08DFSceCEX9unCuMcT72rAQlLpdZir876
-----END RSA PRIVATE KEY-----</textarea><br/>
<label for="pubkey">Public Key</label><br/>
<textarea id="pubkey" rows="15" cols="65">-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDwajtN
FOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76
xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4
gwQco1KRMDSmXSMkDwIDAQAB
-----END PUBLIC KEY-----</textarea><br/>
<label for="input">Text to encrypt:</label><br/>
<textarea id="input" name="input" type="text" rows=4 cols=70>This is a test!</textarea><br/>
<label for="output">Text encrypted:</label><br/>
<textarea id="output" name="output" type="text" rows=8 cols=70></textarea><br/>
<input id="testme" type="button" value="Test Me!!!" /><br/>
</body>
</html>