soarli

前端中使用 AES 加密算法的方法和注意事项
AES(Advanced Encryption Standard)是一种由美国国家标准与技术研究院(NIST)于 ...
扫描右侧二维码阅读全文
29
2023/07

前端中使用 AES 加密算法的方法和注意事项

AES(Advanced Encryption Standard)是一种由美国国家标准与技术研究院(NIST)于 2001 年发布的一种标准加密算法,被广泛应用于各种领域,如互联网、金融、通信等。AES 是一种对称加密算法,也就是说,它使用相同的密钥来加密和解密数据。对称加密算法的优点是速度快、安全性高、兼容性好,但缺点是需要保证密钥的安全性和有效性。

在前端中,我们有时也需要使用 AES 加密算法来保护数据的安全性,例如,我们可以使用 AES 加密算法来加密用户的敏感信息,或者使用 AES 加密算法来加密和解密与后端服务器的通信数据。但是,在前端中使用 AES 加密算法也会面临一些挑战,因为前端代码可以被查看和修改,这就给密钥的存储和传输带来了风险。虽然无法完全保证密钥的绝对安全,但可以采取一些措施提高密钥的安全性。

本文将介绍如何使用 AES 算法进行加密和解密,并提供一些前端存储密钥的安全措施。

AES 加密/解密 Demo

为了演示如何使用 AES 算法进行加密和解密,我们可以使用一个 JavaScript 加密库 CryptoJS,它提供了多种加密算法的实现,包括 AES、DES、TripleDES、MD5、SHA-1 等。下面的代码展示了如何使用 CryptoJS 库进行 AES 加密和解密操作。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>AES 加密/解密 Demo</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
</head>
<body>
  <h1>AES 加密/解密 Demo</h1>
  
  <label for="plaintext">明文:</label>
  <input type="text" id="plaintext"><br><br>
  
  <button onclick="encrypt()">加密</button><br><br>
  
  <label for="ciphertext">密文:</label>
  <input type="text" id="ciphertext"><br><br>
  
  <button onclick="decrypt()">解密</button><br><br>
  
  <script>
    function encrypt() {
      // 生成一个 8 字符长度的字符串作为密钥,转换为 32 字节长度的字节数组
      let key = CryptoJS.enc.Utf8.parse("jeH3O1VX");
      // 生成一个 8 字符长度的字符串作为初始化向量 IV,转换为 16 字节长度的字节数组
      let iv = CryptoJS.enc.Utf8.parse("nHnsU4cX");
      // 获取明文数据
      let plaintext = document.getElementById("plaintext").value;
      // 使用 AES 算法、CBC 模式和 Pkcs7 填充方式进行加密,返回加密后的字符串
      let encrypted = CryptoJS.AES.encrypt(plaintext, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      });
      // 将密文数据显示在页面上
      document.getElementById("ciphertext").value = encrypted.toString();
    }

    function decrypt() {
      // 使用相同的密钥和初始化向量 IV
      let key = CryptoJS.enc.Utf8.parse("jeH3O1VX");
      let iv = CryptoJS.enc.Utf8.parse("nHnsU4cX");
      // 获取密文数据
      let ciphertext = document.getElementById("ciphertext").value;
      // 使用 AES 算法、CBC 模式和 Pkcs7 填充方式进行解密,返回解密后的字符串
      let decrypted = CryptoJS.AES.decrypt(ciphertext, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      });
      // 将明文数据显示在页面上
      document.getElementById("plaintext").value = decrypted.toString(CryptoJS.enc.Utf8);
    }
  </script>
</body>
</html>

以上代码实现了一个简单的 AES 加密/解密 Demo。在页面中输入明文数据后,点击“加密”按钮,即可将明文数据使用 AES 算法加密。加密时需要指定一个密钥和一个初始化向量 IV,这里使用的密钥是 jeH3O1VX,IV 是 nHnsU4cX。加密完成后,将密文数据显示在页面上。点击“解密”按钮,可以将密文数据解密为明文数据。解密时需要使用相同的密钥和 IV。

下图展示了加密和解密的过程:

从图中可以看出,加密和解密的结果是一致的,说明 AES 算法是可逆的。同时,也可以看出,密文数据是一串看似无意义的字符,这说明 AES 算法是可靠的,不容易被破解。

加密算法实现细节

为了更好地理解 AES 加密算法的原理和步骤,我们可以深入了解一下加密算法的实现细节。以下是一些 AES 加密算法实现的细节:

密钥生成

在进行 AES 加密操作时,需要使用一个密钥来加密数据。密钥的长度可以是 128 位、192 位或 256 位。不同的密钥长度对应不同的加密强度和加密轮数。加密强度是指密钥的复杂度和随机性,加密轮数是指加密算法执行的次数。一般来说,密钥长度越长,加密强度越高,加密轮数越多,加密效果越好,但也会消耗更多的时间和资源。

在本例中,我们使用一个 8 字符长度的字符串作为密钥,这个字符串会被转换成 32 字节长度的字节数组。这相当于使用了一个 256 位的密钥,对应的加密轮数是 14 轮。具体实现如下:

let key = CryptoJS.enc.Utf8.parse("jeH3O1VX"); 

初始化向量 IV

在 CBC(Cipher Block Chaining)模式下,需要指定一个初始化向量 IV。CBC 模式是一种常用的加密模式,它的特点是每个明文块的加密结果都依赖于前一个明文块的加密结果,这样可以增加加密的复杂度和随机性,防止重复的明文块产生相同的密文块。IV 的作用是作为第一个明文块的前一个明文块的加密结果,这样可以避免第一个明文块的加密结果与其他明文块的加密结果相同。

IV 的长度与块大小一致,在 AES 中块大小固定为 128 位,因此 IV 的长度也应为 128 位。在本例中,我们使用一个 8 字符长度的字符串作为 IV,这个字符串会被转换成 16 字节长度的字节数组。具体实现如下:

let iv = CryptoJS.enc.Utf8.parse("nHnsU4cX"); 

加密操作

使用 AES 加密算法进行加密时,需要指定加密模式和填充方式。加密模式是指加密算法的工作方式,不同的加密模式有不同的特点和适用场景。填充方式是指在加密前对明文数据进行补齐的方法,以使明文数据的长度符合加密算法的要求。在本例中,我们使用 CBC 模式和 Pkcs7 填充方式。CBC 模式是一种常用的加密模式,它的特点是每个明文块的加密结果都依赖于前一个明文块的加密结果,这样可以增加加密的复杂度和随机性,防止重复的明文块产生相同的密文块。Pkcs7 填充方式是一种常用的填充方式,它的特点是在明文数据的末尾添加 N 个字节,每个字节的值都是 N,其中 N 是需要补齐的字节数,如果明文数据的长度刚好符合要求,则添加一个完整的块,即 16 个字节,每个字节的值都是 16。

加密完成后,使用 toString() 方法将加密结果转换为字符串。具体实现如下:

let encrypted = CryptoJS.AES.encrypt(plaintext, key, {  iv: iv,  mode: CryptoJS.mode.CBC,  padding: CryptoJS.pad.Pkcs7 }); document.getElementById("ciphertext").value = encrypted.toString(); 

下图展示了 AES 加密算法的原理和步骤:

从图中可以看出,AES 加密算法的核心是一个 4x4 的矩阵,称为状态(state)。状态的每个元素是一个字节,因此状态的大小为 128 位,与块大小一致。加密算法的每一轮都对状态进行四个操作:字节代换(SubBytes)、行移位(ShiftRows)、列混合(MixColumns)和轮密钥加(AddRoundKey)。这四个操作的目的是将明文数据和密钥进行混合和变换,以达到加密的效果。加密算法的最后一轮不进行列混合操作,以保证解密算法的可逆性。

解密操作

使用 AES 加密算法进行解密时,需要指定解密模式和填充方式。解密模式和填充方式应与加密时使用的一致,以保证解密的正确性。在本例中,我们使用 CBC 模式和 Pkcs7 填充方式。解密完成后,使用 toString() 方法将解密结果转换为字符串。具体实现如下:

let decrypted = CryptoJS.AES.decrypt(ciphertext, key, {  iv: iv,  mode: CryptoJS.mode.CBC,  padding: CryptoJS.pad.Pkcs7 }); document.getElementById("plaintext").value = decrypted.toString(CryptoJS.enc.Utf8); 

下图展示了 AES 解密算法的原理和步骤:

从图中可以看出,AES 解密算法的核心也是一个 4x4 的矩阵,称为状态(state)。状态的每个元素是一个字节,因此状态的大小为 128 位,与块大小一致。解密算法的每一轮都对状态进行四个操作:逆字节代换(InvSubBytes)、逆行移位(InvShiftRows)、逆列混合(InvMixColumns)和轮密钥加(AddRoundKey)。这四个操作的目的是将密文数据和密钥进行还原和逆变换,以达到解密的效果。解密算法的第一轮不进行逆列混合操作,以保证解密算法的对称性。

存储密钥的安全措施

由于前端代码可以被查看和修改,因此在前端中存储密钥会面临一些挑战。为了提高密钥的安全性,可以采取以下措施:

服务器端加密

将加密操作放到后端服务器上进行,前端只负责传输数据和接收结果。这样可以避免将密钥暴露在前端代码中。例如,我们可以使用 HTTPS 协议来保证数据的安全传输,然后在服务器端使用 AES 加密算法来加密数据,再将加密后的数据返回给前端。

密钥交换协议

使用安全的密钥交换协议,如 Diffie-Hellman 密钥交换,以确保密钥在传输过程中的安全性。Diffie-Hellman 密钥交换是一种公钥加密的方法,它的特点是可以在不安全的信道上安全地交换密钥,而不需要事先共享密钥。例如,我们可以使用 Diffie-Hellman 密钥交换协议来在前端和后端之间生成一个共享的密钥,然后使用该密钥来进行 AES 加密和解密操作。

动态生成密钥

通过动态生成密钥来增加安全性。可以使用前端生成随机数,然后将该随机数发送到服务器进行加密,服务器返回加密后的结果。这样密钥不会在前端代码中明文存在。例如,我们可以使用 Math.random() 函数来生成一个随机数,然后使用该随机数作为密钥来进行 AES 加密和解密操作。

密钥保护

采用访问控制和权限管理等机制来保护密钥的访问。限制只有授权的用户或系统可以访问密钥,减少密钥泄露的风险。例如,我们可以使用 JWT(JSON Web Token)等技术来实现用户的身份认证和授权,然后根据用户的角色和权限来分配不同的密钥。

使用多重加密

使用多个密钥进行层层加密,增加破解的难度。可以采用对称加密与非对称加密结合的方式。例如,我们可以使用 RSA 算法来加密 AES 的密钥,然后使用 AES 算法来加密数据,这样就实现了两层加密。

需要根据具体的应用场景和安全需求来选择适当的措施,综合考虑安全性与实际可行性。同时,也要定期审查和更新密钥,以保持系统的安全性。

总结

本文介绍了如何使用 CryptoJS 库进行 AES 加密和解密操作,以及存储密钥的安全措施。AES 加密算法是一种广泛使用的对称加密算法,可以用于保护数据的安全性。在进行加密操作时,需要使用一个密钥来加密数据,并在解密时使用相同的密钥来还原明文数据。密钥的安全性是确保加密算法的有效性和数据的保护的关键。在前端中存储密钥会面临一些挑战,但可以采取一些措施提高密钥的安全性。

参考资料:

AES加密算法原理及实现_aes密钥扩展-CSDN博客

什么是AES加密?详解AES加密算法原理流程 - 知乎 (zhihu.com)

简单逆向某色情网站图片加密(原创) - 韩小韩博客 - 要变得更加完美。 (vvhan.com)

JS中利用CryptoJS进行MD5/SHA256/BASE64/AES加解密的方法与示例 - 知乎 (zhihu.com)

前端加密JS库--CryptoJS 使用指南 - Tommy_marc - 博客园 (cnblogs.com)

【安全与协议】使用crypto.js进行加密详解_cryptojs详解-CSDN博客

最后修改:2023 年 12 月 29 日 05 : 01 AM

发表评论