1. 程式人生 > >java 使用jsencrypt的js的rsa庫實現rsa加密傳輸,防止http明文傳輸

java 使用jsencrypt的js的rsa庫實現rsa加密傳輸,防止http明文傳輸

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>