使用 Crypto-JS 可以非常方便地在 JavaScript 进行 MD5、SHA1、SHA2、SHA3、RIPEMD-160 哈希散列,进行 AES、DES、Rabbit、RC4、Triple DES 加解密。
Crypto-JS 相关 encrypt 函数会并不直接返回字符串,需要调用返回对象的 toString 方法,或者通过 Crypto-JS 转码才能得到真实的结果。
前端AES使用
// 官方示例, 每次输出的密文都不一样CryptoJS.AES.encrypt("Message", "Secret Passphrase");// 正确用法var str = '123456';// 密钥 16 位var key = '0123456789abcdef';// 初始向量 initial vector 16 位var iv = '0123456789abcdef';// key 和 iv 可以一致key = CryptoJS.enc.Utf8.parse(key);iv = CryptoJS.enc.Utf8.parse(iv);var encrypted = CryptoJS.AES.encrypt(str, key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});// 转换为字符串encrypted = encrypted.toString();// mode 支持 CBC、CFB、CTR、ECB、OFB, 默认 CBC// padding 支持 Pkcs7、AnsiX923、Iso10126// 、NoPadding、ZeroPadding, 默认 Pkcs7, 即 Pkcs5var decrypted = CryptoJS.AES.decrypt(encrypted, key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7});// 转换为 utf8 字符串decrypted = CryptoJS.enc.Utf8.stringify(decrypted);// 引入其他加密模式, 填充模式需要引入对应的 js 文件/*cryptojs/components/mode-cfb-min.jscryptojs/components/mode-ctr-min.jscryptojs/components/mode-ecb-min.jscryptojs/components/mode-ofb-min.jscryptojs/components/pad-ansix923-min.jscryptojs/components/pad-iso10126-min.jscryptojs/components/pad-iso97971-min.jscryptojs/components/pad-nopadding-min.js*/
IV称为初始向量
AES加密需要:明文 + 密钥+ 偏移量(IV)+密码模式(算法/模式/填充)
AES解密需要:密文 + 密钥+ 偏移量(IV)+密码模式(算法/模式/填充)
mode 支持 CBC、CFB、CTR、ECB、OFB, 默认 CBC
padding 支持 Pkcs7、AnsiX923、Iso10126、NoPadding、ZeroPadding, 默认 Pkcs7, 即 Pkcs5
mode === ECB 时, 不需要 iv
java AES使用
java提供AES算法支持。支持的密钥长度为:128, 192, 或256位。由于美国进出口限制,默认的jre只支持128位,也就是16个字节的密钥。
支持的工作模式:
NONE
CBC
CCM
CFB, CFBx
CTR
CTS
ECB
GCM
OFB, OFBx
PCBC
支持的填充方式:
NoPadding
ISO10126Padding
OAEPPadding
PKCS1Padding
PKCS5Padding
SSL3Padding
当使用Cipher.getInstance(“AES”)时,默认获取的是AES/ECB/PKCS5Padding对应的实例。实际使用中这里一定要注意一下,建议实际应用中一定要显示指定工作模式和填充方式。若不显示指定,在跨语言、跨类库或跨系统调用时,容易踩坑。
java 和 js互相加解密问题
java和js互相加解密时,如果不指定工作模式和填充方式,会失败。在js中,一般使用crypto-js库来加解密。但是该类库默认的工作模式是CBC,默认填充方式PKCS7,与java的默认方式不一致。
很多同学在使用AES算法时,不显示指定工作模式和填充方式,在这里就会屡屡出错。问题就出在java和js(crypto-js)默认的工作模式和填充方式不一致。这里只要将两者的工作模式和填充指定一样即可。
第一种方式: js采用AES/CBC/ZeroPadding方式加密。由于java没有提供ZeroPadding填充方式,可以使用AES/CBC/NoPadding方式解密,解密后从后往前依次剔除0x00的字节,遇到非0x00的字节时停止。剩下的字节就是解密后的结果。不过,这种方式需要注意,原始文本转byte数组后,最后一个字节不能是0x00。如果是java加密,js解密,将过程反过来即可。
第二种方式(推荐使用):
前端: AES/CBC/Pkcs7 + iv
后端: AES/CBC/Pkcs5 + iv
相关链接: https://yyhan.github.io/2017/06/26/java-AES%E4%BD%BF%E7%94%A8/
