前端AES加密详解

项目里来来回回一直在用aes,有些时候总会出现和别人加解密不一致的情况,也没看到具体说明很详细的文章,自己花时间研究搜集整理了一下。

一、编码格式

要弄懂aes加解密,首先得先清除编码格式。简单列举说明几种编码格式。

1.base64编码

Base64 编码是通过使用一组 64 个不同的字符表示二进制数据来实现的,包括小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"一共64个字符的字符集。

2.Hex编码(十六进制编码)

Hex编码(也称为十六进制编码)是一种将数据转换为十六进制表示形式的编码方法。与base64编码不同,Hex编码使用16个字符来表示数据,这16个字符分别是0-9的数字和A-F的字母(不区分大小写,即a-f和A-F是等价的)。

3.Unicode编码

Unicode编码是一个用于表示字符的编码标准,它允许使用16位或32位的整数序列来表示字符,具体取决于使用的Unicode编码格式。Unicode编码包括但不限于、UTF-8和UTF-7等,每种编码方式都有其特定的应用场景和优缺点。

二、AES前端加密方法

首先要用到crypto-js库,里面包含很多加密方法,我们使用其中的aes加密方法。

1.安装前端加密库crypto-js
npm install crypto-js
2.引入crypto-js
import CryptoJS from 'crypto-js'
3.密钥

aes属于对称加密,加密解密都使用同一个密钥。这里不详细解释,对加密感兴趣的可以自己学习密码学相关知识。aes的密钥长度可以是16字节,24字节,32字节。(1字节=8位,可以使用16位base64编码,32位Hex编码)

4.crypto-js的加密方法
 CryptoJS.AES.encrypt(data, key, {
    iv:iv,
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  });

该方法接受三个参数,第一个是加密的数据(data),第二个是加密的秘钥(key),第三个是加密方法对象,该对象能接受三个值:iv表示偏移量(CBC模式特有),mode表示加密模式,padding表示填充方式(加解密数据不满16位用于填充的方法)

这是crypto-js提供的加密方法,理论上如果传入字符串类型的参数,方法内部会自动转为WordArray格式。但是为保证规范,我们将上述传入参数都转换为WordArray格式。下面是官网提供各种编码转化方式:

CryptoJS.AES.encrypt方法加密后的结果是一个对象,其中包含了加密后的数据。这个对象通常包含以下属性:

  • ciphertext: 加密后的数据,以WordArray对象的形式存储。

  • key: 加密使用的密钥,以WordArray对象的形式存储。

  • iv: 加密使用的初始化向量(IV),以WordArray对象的形式存储。

    所以根据需要加密的编码格式这边可以得到最简单的一个加密过程,下面方法中默认传入的为utf-8编码格式数据,结果输出的是bsae64格式密文。这边注意还有个比较常用的密文输出是Hex编码,通常可以用toString()方法代替CryptoJS.enc.Hex.stringify(),即encrypted.ciphertext.toString()就是将WordArray对象格式转化为Hex编码返回。

    function aesEncryptCBC(key,data,iv) {
      //将key,data,iv都转化为wordarry格式,根据传入的编码格式选择对应的方法
      key = CryptoJS.enc.Utf8.parse(key);
      iv   = CryptoJS.enc.Utf8.parse(iv);
      data= CryptoJS.enc.Utf8.parse(data)
      var encrypted = CryptoJS.AES.encrypt(data, key, {
        iv:iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      });
    //这里返回的是Base64的密文
      return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
    }
    
    5.crypto-js的解密方法

    同加密方法提到的一些注意点,不再赘述,以下代码中的toString(CryptoJS.enc.Utf8)等同于CryptoJS.enc.Utf8.stringify(encrypted.ciphertext),都是将WardArray转化为utf8编码格式,可以自行选择。

    function aesDecrypt(key,encrypted,iv) {
      key = CryptoJS.enc.Utf8.parse(key);
      encrypted = CryptoJS.enc.Base64.parse(encrypted);
      iv   = CryptoJS.enc.Utf8.parse(iv);
      var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
        iv:iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      });
      return decrypted.toString(CryptoJS.enc.Utf8);
    }

    三、总结

    主要还是搞清楚各种编码的格式以及CryptoJS提供的WordArray格式转化的方法。其他都是一些基础的传参及取值问题。最后提一个注意点,AES是对称加密,前端加密秘钥总还是没有那么安全,建议采用非对称加密。