客戶端和服務端數據加解密流程圖
案例
1、客戶端生成aes秘鑰
jsfunction getAesKey(len) {
len = len || 32;
var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默認去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
var maxPos = $chars.length;
var keyStr = '';
for(i = 0; i < len; i++) {
keyStr += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return keyStr;
}
2、客戶端生成公鑰
jsvar pubKey = new RSAKeyPair(public_exponent, "", modulus);
//生成公鑰,這里的public_exponent和modulus是從服務端獲取,便於服務端可以定時更新公鑰
3、 客戶端aesKey轉成base64
jsvar keyStr64=encode64(keyStr);
4、客戶端生成RSA公鑰
jssetMaxDigits(130);//BigInt.js
var pubKey = new RSAKeyPair(public_exponent, "", modulus); //獲得rsa公鑰
5、用公鑰加密AES密鑰
jsvar aesKeyMi = encryptedString(pubKey, keyStr64, RSAAPP.NoPadding, RSAAPP.NumericEncoding);
//此處的keyStr64是AES密鑰轉成base64后的值
6、用客戶端生成的AES密鑰加密入參
jsvar 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"), 16);
BigInteger privateExponent = new BigInteger(new String(Base64.decodeBase64(privateExponentStr), "UTF-8"), 16);
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() / 8;
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、
javapublic 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、服務端處理完業務后,返回加密的數據
javapublic 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;
}