基于AES的密文加解密
什么是AES
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),又称Rijndael加密法(荷兰语发音: [ˈrɛindaːl],音似英文的“Rhine doll”),是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。现在,高级加密标准已然成为对称密钥加密中最流行的算法之一。
在密码学中有对称加密与非对称加密,AES属于对称加密,RSA属于非对称加密,我们这里只讨论AES的应用
基本使用
- 需要引入的模块:
const CryptoJS = require('crypto-js')
- 定义密钥KEY,KEY可以是任何字符串,用于加密也解密文本,我们假设为
HOWDUUDU
- 加密文本:假设我们的密码是
8879576hdud
,输入CryptoJS.AES.encrypt('8879576hdud', 'HOWDUUDU').toString()
,输出密文U2FsdGVkX1+N4vlBhSYzxlN075knzFQk4l4VsxT71h0=
,该字符串就是AES加密后的密文,此处密文不是唯一的,每次执行都会生成不一样的密文 - 解密文本:第三步获得加密文本,接下来我们进行解密,输入
CryptoJS.AES.decrypt('U2FsdGVkX1+N4vlBhSYzxlN075knzFQk4l4VsxT71h0=', 'HOWDUUDU').toString(CryptoJS.enc.Utf8)
,执行后输出的正是我们的加密文本8879576hdud
AES加密解密的关键是密钥,有了密钥破解密文就很简单,如果没有密钥想要进行暴力破解就比较困难了,至少256位的加密想要暴力破解现在想都不用想,据说几年前有量子计算机暴力破解了128位加密的密文
高级使用
AES加密方法还有第三个入参,这个入参定义了机密算法使用的模式(mode)、填充(padding)及初始化向量(iv, Initialization vector)
CryptoJS.AES.encrypt(明文, 密钥, {
iv: 初始化向量,
mode: CryptoJS.mode.CFB,
padding: CryptoJS.pad.Pkcs7
})
模式(mode)
CryptoJS支持的模式如下,其中CBC是默认模式,由于ECB将相同的明文块加密为相同的密文块,因此ECB模式不建议使用
Mode | Formulas | Ciphertext |
---|---|---|
Electronic codebook (ECB) | Yi = F(PlainTexti, Key) | Yi |
Cipher block chaining (CBC) | Yi = PlainTexti XOR Ciphertexti−1 | F(Y, Key); Ciphertext0 = IV |
Propagating CBC (PCBC) | Yi = PlainTexti XOR (Ciphertexti−1 XOR PlainTexti−1) | F(Y, Key); Ciphertext0 = IV |
Cipher feedback (CFB) | Yi = Ciphertexti−1 | Plaintext XOR F(Y, Key); Ciphertext0 = IV |
Output feedback (OFB) | Yi = F(Yi−1, Key); Y0 = F(IV, Key) | Plaintext XOR Yi |
Counter (CTR) | Yi = F(IV + g(i), Key); IV = token() | Plaintext XOR Yi |
填充(padding)
由于AES是块(分组)加密,会存在最后一块空间字节占位不满的情况,因此padding用于定义填充方式,对应的解密时要知道填充方式好去掉最后一块空间中的无用填充。
CryptoJS支持的填充方式有: Pkcs7(默认)、Iso97971、AnsiX923、Iso10126、ZeroPadding、NoPadding
具体填充介绍可移步维基百科Padding 🔗
初始化向量(iv, Initialization vector)
初始化向量(IV)挺让人模糊的,因为这个IV和密钥作用好像很像,其实不然,这是我的理解:
AES是块(分组)加密的,每一块内容都需要用密钥转换,然而密钥是不变的,那么相同内容转换后的字节码也是一样,这样是不安全的,因此解决这种不安全就要用到IV,初始化向量(IV)的意思是我们只传递第一个块的向量值,接下来的每一块的向量值都是通过上一个块生成,这样每一块的向量值都是不一样的,然后AES通过密钥加向量值对明文加密,由于每一个加密区块的向量值不一样,因此加密得出的区块字节码也不一致。
IV的长度与AES的加密位数有关,AES-128是16字节,AES-192是24字节,AES-256是32字节,当长度超过或者不足时,会自动截断或填充。
本文使用的CryptoJS.AES为AES-128因此为16字节,可使用CryptoJS.enc.Utf8.parse方法转换,且入参要为16个字符。
具体填充介绍可移步维基百科InitializationVector 🔗
使用示例
注意:明文、密文与初始化向量需要使用CryptoJS.enc.Utf8.parse
转换,否则iv不起作用
该示例mode使用CBC,填充使用Pkcs7
var CryptoJS = require('crypto-js');
// 定义明文
var text = CryptoJS.enc.Utf8.parse('8879576hdud');
// 定义密钥
var key = CryptoJS.enc.Utf8.parse("HOWDUUDU");
// 定义初始化向量
var iv = CryptoJS.enc.Utf8.parse("HOWDUUDUHOWDUUDU");
// 加密
var cryptText = CryptoJS.AES.encrypt(text, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// 解密
CryptoJS.AES.decrypt(cryptText, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8)
后记
具体可查看维基百科(分组密码操作模式)[https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation 🔗]
对称加密虽然难以暴力破解,但是可以通过社会工程学+旁道攻击获取到密钥,那么密文破解自然也就没难度了,因此一般AES是结合RAS一起使用,如常见的HTTPS协议