后端:Java语言实现
public class AESTest { //static String data = "123456RWEQR"; static String key = "abcdef0123456789"; //16位 static String iv = "0123456789abcdef"; //16位 public static void main(String args[]) throws Exception { System.out.println(encryptAES("123456")); System.out.println(decryptAES(encryptAES("123456"))); } public static String encryptAES(String data) throws Exception { try { Cipher cipher = Cipher.getInstance("AES/CBC/NOPadding"); //参数分别代表 算法名称/加密模式/数据填充方式 int blockSize = cipher.getBlockSize(); byte[] dataBytes = data.getBytes(); int plaintextLength = dataBytes.length; if (plaintextLength % blockSize != 0) { plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize)); } byte[] plaintext = new byte[plaintextLength]; System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length); SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); byte[] encrypted = cipher.doFinal(plaintext); return new sun.misc.BASE64Encoder().encode(encrypted); } catch (Exception e) { e.printStackTrace(); return null; } } public static String decryptAES(String data) throws Exception { try { byte[] encrypted1 = new BASE64Decoder().decodeBuffer(data); Cipher cipher = Cipher.getInstance("AES/CBC/NOPadding"); SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); byte[] original = cipher.doFinal(encrypted1); String originalString = new String(original); return originalString; } catch (Exception e) { e.printStackTrace(); return null; } } } 前端 JS实现
1.引入需要引入 aes.js依赖包 密码:k9mc
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>AES TEST</title> </head> <body> <p>待加密值:123456RWEQR</p> <p id="p1"></p> <p id="p2"></p> <script type="text/javascript" src="js/vendor/jquery-1.12.0.min.js"></script> <script type="text/javascript" src="js/aes/aes.js"></script> <script type="text/javascript" src="js/aes/pad-zeropadding.js"></script> <script type="text/javascript"> $(function () { var data = "123456RWEQR"; var key = CryptoJS.enc.Latin1.parse('abcdef0123456789'); var iv = CryptoJS.enc.Latin1.parse('0123456789abcdef'); //加密 var encrypted = CryptoJS.AES.encrypt(data, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding }); $("#p1").text("加密结果:"+encrypted.toString()); console.log(encrypted.toString()) //解密 var decrypted = CryptoJS.AES.decrypt(encrypted, key, {iv: iv, padding: CryptoJS.pad.ZeroPadding}); console.log(decrypted.toString(CryptoJS.enc.Utf8)); $("#p2").text("解密结果:"+decrypted.toString(CryptoJS.enc.Utf8)); }) </script> </body> </html>
AES四种常用的加密模式
对称/分组密码一般分为流加密(如OFB、CFB等)和块加密(如ECB、CBC等)。对于流加密,需要将分组密码转化为流模式工作。对于块加密(或称分组加密),如果要加密超过块大小的数据,就需要涉及填充和链加密模式。
一、 ECB(Electronic Code Book电子密码本)模式
ECB模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密密钥长度相同,然后每组都用相同的密钥进行加密。
优点:
1.简单; 2.有利于并行计算; 3.误差不会被传送;
缺点: 1.不能隐藏明文的模式; 2.可能对明文进行主动攻击; 因此,此模式适于加密小消息。
二、CBC(Cipher Block Chaining,加密块链)模式
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点: 1.不利于并行计算; 2.误差传递; 3.需要初始化向量IV且必须是16字节
三、CFB(Cipher FeedBack Mode,加密反馈)模式
优点:
1.隐藏了明文模式; 2.分组密码转化为流模式; 3.可以及时加密传送小于分组的数据;
缺点: 1.不利于并行计算; 2.误差传送:一个明文单元损坏影响多个单元; 3.唯一的IV;
四、OFB(Output FeedBack,输出反馈)模式
优点:
1.隐藏了明文模式; 2.分组密码转化为流模式; 3.可以及时加密传送小于分组的数据;
缺点: 1.不利于并行计算; 2.对明文的主动攻击是可能的; 3.误差传送:一个明文单元损坏影响多个单元
AES三中数据填充方式
PKCS7Padding
Java不支持此方式
PKCS7Padding是缺几个字节就补几个字节的0
PKCS5Padding
JS不支持此方式
PKCS5Padding是缺几个字节就补充几个字节的几,例如缺8个字节,就补充8个字节的8
NOPadding
不补充字节
ts模式下+CryptoJS插件实现前端解密
decryptByAes(ciphertext) { function aesDecrypt(encrypted, key,iv) { key = CryptoJS.enc.Latin1.parse(key); iv=CryptoJS.enc.Latin1.parse(iv); let decrypted = CryptoJS.AES.decrypt(encrypted, key, {iv: iv, padding: CryptoJS.pad.ZeroPadding}); let content = CryptoJS.enc.Utf8.stringify(decrypted); return content; } const formatDate = () => { // 格式化日期,获取今天的日期 const Dates = new Date(); const year: number = Dates.getFullYear(); const month: any = (Dates.getMonth() + 1) < 10 ? '0' + (Dates.getMonth() + 1) : (Dates.getMonth() + 1); const day: any = Dates.getDate() < 10 ? '0' + Dates.getDate() : Dates.getDate(); return year + month + day; } let key=formatDate()+'10010@zc'; //秘钥是日期+字符串 let iv=formatDate()+'10010@cz'; let decrypt = aesDecrypt(ciphertext, key,iv); return decrypt; }