目录:
  1. 基于AES的密文加解密
    1. 什么是AES
      1. 基本使用
        1. 高级使用
          1. 模式(mode)
          2. 填充(padding)
          3. 初始化向量(iv, Initialization vector)
          4. 使用示例
        2. 后记

        基于AES的密文加解密

        阅读时间:全文 1200 字,预估用时 6 分钟
        创作日期:2021-11-16
        文章标签:
         
        BEGIN

        什么是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的应用

        基本使用

        1. 需要引入的模块:const CryptoJS = require('crypto-js')
        2. 定义密钥KEY,KEY可以是任何字符串,用于加密也解密文本,我们假设为HOWDUUDU
        3. 加密文本:假设我们的密码是8879576hdud,输入CryptoJS.AES.encrypt('8879576hdud', 'HOWDUUDU').toString(),输出密文U2FsdGVkX1+N4vlBhSYzxlN075knzFQk4l4VsxT71h0=,该字符串就是AES加密后的密文,此处密文不是唯一的,每次执行都会生成不一样的密文
        4. 解密文本:第三步获得加密文本,接下来我们进行解密,输入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模式不建议使用

        ModeFormulasCiphertext
        Electronic codebook (ECB)Yi = F(PlainTexti, Key)Yi
        Cipher block chaining (CBC)Yi = PlainTexti XOR Ciphertexti−1F(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−1Plaintext 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协议

        FINISH

        随机文章
        人生倒计时
        default