天天看點

AES+RSA加密解密(js和java互通)

用戶端和服務端資料加解密流程圖

AES+RSA加密解密(js和java互通)

案例

1、用戶端生成aes秘鑰

js

function getAesKey(len) {  
    len = len || ;  
    var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****預設去掉了容易混淆的字元oOLl,9gq,Vv,Uu,I1****/   
    var maxPos = $chars.length;  
    var keyStr = '';  
    for(i = ; i < len; i++) {    
        keyStr += $chars.charAt(Math.floor(Math.random() * maxPos));  
    }  
    return keyStr;
}
           

2、用戶端生成公鑰

js

var pubKey = new RSAKeyPair(public_exponent, "", modulus); 
//生成公鑰,這裡的public_exponent和modulus是從服務端擷取,便于服務端可以定時更新公鑰
           

3、 用戶端aesKey轉成base64

js

4、用戶端生成RSA公鑰

js

setMaxDigits();//BigInt.js
var pubKey = new RSAKeyPair(public_exponent, "", modulus); //獲得rsa公鑰
           

5、用公鑰加密AES密鑰

js

var aesKeyMi = encryptedString(pubKey, keyStr64, RSAAPP.NoPadding, RSAAPP.NumericEncoding); 
//此處的keyStr64是AES密鑰轉成base64後的值
           

6、用用戶端生成的AES密鑰加密入參

js

var msg_source = "0102030405060708";
//此處的iv向量和服務端保持一緻
var iv = CryptoJS.enc.Utf8.parse(msg_source);
tool.encrypt = function(data) {
    //AES加密
    var key = CryptoJS.enc.Utf8.parse(keyStr);
    var srcs = CryptoJS.enc.Utf8.parse(data);
    var encrypted = CryptoJS.AES.encrypt(srcs, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC
    });

    return encrypted;
}
           

7、用戶端的入參形式

{"key":aesKeyMi,"param":"此處為加密後的參數"}
           

8、服務端擷取AES密鑰

java

/** 
 * 私鑰解密 
 *  
 * @param key 接口入參的key
 * @return 
 * @throws Exception 
 */  
public static String getKey(String key) throws Exception {
    //擷取經過rsa非對稱加密的 用戶端生成的aes密鑰 
    if(StringUtils.nullOrBlank(key)) {
        return "";
    }
    RSAPrivateKey privateKey = null;
    try {
        String privateExponentStr = ENVUtils.getPrivateExponent();//本案例中的privateExponentStr通過配置檔案設定
        String modulusStr = ENVUtils.getModulus();//本案例中的modulusStr通過配置檔案設定
        BigInteger modulus = new BigInteger(new String(Base64.decodeBase64(modulusStr), "UTF-8"), );
        BigInteger privateExponent = new BigInteger(new String(Base64.decodeBase64(privateExponentStr), "UTF-8"), );
        privateKey = RSAUtils.getPrivateKey(modulus, privateExponent);
        return RSAUtils.decryptByPrivateKey(key, privateKey);
    }catch(Exception e) {
        logger.error("擷取私鑰失敗", e);
        return "";
    }
}
           

RSAUtils相關代碼

public static RSAPrivateKey getPrivateKey(BigInteger modulus, BigInteger exponent) {
    try {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA", RSA_RPOVIDER);
        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulus, exponent);
        return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
    } catch (Exception e) {
        logger.error("合成私鑰異常", e);
        return null;
    }
}
/** 
 * 私鑰解密 
 *  
 * @param data 
 * @param privateKey 私鑰
 * @return 
 * @throws Exception 
 */  
public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding", RSA_RPOVIDER);
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    // 模長
    int key_len = privateKey.getModulus().bitLength() / ;
    byte[] b = StringUtils.decodeHex(data);
    // 如果密文長度大于模長則要分組解密
    String ming = "";
    byte[][] arrays = splitArray(b, key_len);
    for (byte[] arr : arrays) {
        ming += new String(cipher.doFinal(arr));
    }
    return ming;
} 
           

9、服務端用AES密鑰解密入參param、

java

public static String aesDecrypt(String encryptStr, String decryptKey)
        throws Exception {
    if(StringUtils.nullOrBlank(decryptKey)) {
        return encryptStr;
    }
    return aesDecryptByBytes(
            base64Decode(encryptStr), decryptKey);
}
public static String aesDecryptByBytes(byte[] encryptBytes,
        String decryptKey) throws Exception {
    byte[] keys = base64Decode(decryptKey);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//此處的部位方式應該跟用戶端保持一緻CryptoJS.mode.CBC
    IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());//此處的向量應該跟用戶端保持一緻0102030405060708
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keys, "AES"), iv);
    byte[] decryptBytes = cipher.doFinal(encryptBytes);

    return new String(decryptBytes, "utf-8");
}
public static byte[] base64Decode(String base64Code) throws Exception {
    return base64Code == null ? null : Base64.decodeBase64(base64Code);
}
           

10、服務端處理完業務後,傳回加密的資料

java

public static String aesEncrypt(String content, String encryptKey)
        throws Exception {
    if(StringUtils.nullOrBlank(encryptKey)) {
        return content;
    }
    return base64Encode(aesEncryptToBytes(content, encryptKey));
}
public static byte[] aesEncryptToBytes(String content, String encryptKey)
        throws Exception {
    byte[] keys = base64Decode(encryptKey);
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//此處的部位方式應該跟用戶端保持一緻CryptoJS.mode.CBC
    IvParameterSpec iv = new IvParameterSpec("0102030405060708".getBytes());//此處的向量應該跟用戶端保持一緻0102030405060708
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keys, "AES"), iv);
    return cipher.doFinal(content.getBytes("utf-8"));
}
public static String base64Encode(byte[] bytes) {
    return Base64.encodeBase64String(bytes);
}
           

11、用戶端解密出參dataMi

js

//AES解密
var msg_source = "0102030405060708";
//此處的iv向量和服務端保持一緻
var iv = CryptoJS.enc.Utf8.parse(msg_source);
tool.decrypt = function(data) {
    var key = CryptoJS.enc.Utf8.parse(aesKey);
    var decrypt = CryptoJS.AES.decrypt(data, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC
    });
    var rtnStr = CryptoJS.enc.Utf8.stringify(decrypt).toString();
    mConsole("11111" + rtnStr);
    return rtnStr;
}
           

附上本文需要用到的[js檔案和jar(主要是jdk自帶包)包]

(http://download.csdn.net/download/qq_18837459/9898084)

PS:我已經備注了下載下傳檔案隻有jar包和js檔案,java代碼在上面例子裡面已經有了,自己看一下就懂了,覺得需要給一個完整demo才行的,請慎下。

http://www.ohdave.com/rsa/ javascript的rsa加密算法