簡述
- 如題,最近項目需要選擇一套對稱加密算法,來滿足前后端之間的加解密操作。
- 初步打算前端使用crypto-js來實現,后端使用java本身的加密算法實現
- 但,遇到了一個問題:java本身只支持NoPadding和PKCS5Padding,如下圖:
- 而crypto-js提供的padding包括如下圖,沒有PKCS5Padding,所以不得以,前后端最終使用PKCS7Padding來實現功能
前端
- npm i crypto-js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script type="text/javascript" src="node_modules/crypto-js/crypto-js.js"></script>
</head>
<body>
<script type="text/javascript">
// 偏移量
let iv = "0000000000000000";
// 加密內容
let message = "abcd中文測試加標點符號!@#¥%……&*(+——)(*&~,。,;,,/;lkk;ki;'[p]./,'\\467646789";
// 密鑰,長度必須為16
let secret_key = "1234567890123456";
// utf-8 轉換
message = CryptoJS.enc.Utf8.parse(message);
secret_key = CryptoJS.enc.Utf8.parse(secret_key);
iv = CryptoJS.enc.Utf8.parse(iv);
// Encrypt
var ciphertext = CryptoJS.AES.encrypt(message, secret_key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(ciphertext.toString());
// Decrypt
var bytes = CryptoJS.AES.decrypt(ciphertext.toString(), secret_key,{
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(bytes.toString(CryptoJS.enc.Utf8));
</script>
</body>
</html>
- 運行結果:
java
package com.sgcc.atc.importUser.Utils.encrypted;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class AESpkcs7paddingUtil {
/**
* 密鑰算法
*/
private static final String KEY_ALGORITHM = "AES";
/**
* 加密/解密算法 / 工作模式 / 填充方式
* Java 6支持PKCS5Padding填充方式
* Bouncy Castle支持PKCS7Padding填充方式
*/
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
/**
* 偏移量,只有CBC模式才需要
*/
private final static String ivParameter = "0000000000000000";
/**
* AES要求密鑰長度為128位或192位或256位,java默認限制AES密鑰長度最多128位
*/
public static String sKey="" ;
/**
* 編碼格式
*/
public static final String ENCODING = "utf-8";
static {
//如果是PKCS7Padding填充方式,則必須加上下面這行
Security.addProvider(new BouncyCastleProvider());
}
/**
* AES加密
* @param source 源字符串
* @param key 密鑰
* @return 加密后的密文
* @throws Exception
*/
public static String encrypt(String source, String key) throws Exception {
byte[] sourceBytes = source.getBytes(ENCODING);
byte[] keyBytes = key.getBytes(ENCODING);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(ENCODING));
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM),iv);
byte[] decrypted = cipher.doFinal(sourceBytes);
return Base64.encodeBase64String(decrypted);
}
/**
* AES解密
* @param encryptStr 加密后的密文
* @param key 密鑰
* @return 源字符串
* @throws Exception
*/
public static String decrypt(String encryptStr, String key) throws Exception {
byte[] sourceBytes = Base64.decodeBase64(encryptStr);
byte[] keyBytes = key.getBytes(ENCODING);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(ENCODING));
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM),iv);
byte[] decoded = cipher.doFinal(sourceBytes);
return new String(decoded, ENCODING);
}
public static void main(String[] args) throws Exception {
String key = "1234567890123456";
// 加密
long lStart = System.currentTimeMillis();
String enString = AESpkcs7paddingUtil.encrypt("abcd中文測試加標點符號!@#¥%……&*(+——)(*&~,。,;,,/;lkk;ki;'[p]./,'\\467646789",key);
System.out.println("加密后的字串是:" + enString);
long lUseTime = System.currentTimeMillis() - lStart;
System.out.println("加密耗時:" + lUseTime + "毫秒");
// 解密
lStart = System.currentTimeMillis();
String DeString = AESpkcs7paddingUtil.decrypt(enString,key);
System.out.println("解密后的字串是:" + DeString);
lUseTime = System.currentTimeMillis() - lStart;
System.out.println("解密耗時:" + lUseTime + "毫秒");
}
}
- 運行結果
** 注意**,因為使用了BouncyCastleProvider和base64的方法,需要引入以下兩個jar包
最后
- 上網查pkcs7 pkcs5區別的時候,發現網上說二者區別不太大,主要就是填充的塊的大小不一致,所以java端嘗試使用了PKCS5Padding來實現相同的功能,發現還真的可以。不過為了規避風險,最終項目還是選擇了上述方案。
- 如果你想降低加密算法難度,提高加解密速度,可以把模式修改成ECB,然后注釋掉偏移量即可。
參考
https://www.cnblogs.com/chen-lhx/p/6233954.html
https://www.npmjs.com/package/crypto-js
https://blog.csdn.net/test1280/article/details/75268255
https://blog.csdn.net/sunqiujing/article/details/75065218