AES 密码——概念
高级加密标准(AES)密码也称为“Rijndael”,是一种流行、安全且广泛使用的对称密钥分组密码算法,并被美国正式列为推荐的加密技术标准。AES 使用 128 位分组大小,支持长度为 128、192 和 256 位的对称密钥。
AES 是安全且非常流行的对称加密算法
AES 对称加密算法在正确配置时被认为高度安全,其历史上尚无已知的重大实用攻击。
如今,大多数互联网网站都在内部使用 AES 提供 https:// 内容;它是用于 Web 主机间安全通信的 TLS(传输层安全)和 SSL(安全套接字层)标准的一部分。
由于 AES 广泛用于互联网安全通信,现代 CPU 硬件在微处理器层面实现了 AES 指令,以加速 AES 加密和解密。
AES 算法参数
AES 算法可以使用不同的密钥长度,但分组大小始终为 128 位。对于大多数应用,128 位 AES 加密(AES-128)已经足够;如需更高的加密强度,建议使用 AES-256(256 位密钥长度)。
与其他分组密码一样,AES 可以采用多种工作模式(CBC、ECB、CTR 等)之一,以加密任意长度的数据。一般场景以及区块链钱包加密推荐使用“CTR”模式。
大多数工作模式都需要一个初始化向量(IV)。例如,使用计数器模式(CTR),即 AES-128-CTR(128 位)或 AES-256-CTR(256 位)时,应先生成一个不保密的随机盐(IV),并将其与加密后的密文输出一同保存。IV 的大小始终与分组大小相同,即 128 位(16 字节)。
AES 加密与 CTR 分组模式及随机 IV 结合后,即使加密相同的输入数据,算法每次也会生成不同的密文。这可以防止他人构建字典来逆向还原密文。
CBC 模式下的 AES 加密使用填充算法(如 PKCS7 或 ANSI X.923),以便在将数据块传给 AES-CBC 算法之前,把输入数据拆分为固定大小(如 128 位)的分组。大多数开发者对 AES 使用 CTR 模式,因此不需要填充。
不使用分组模式时,AES 算法生成的密文与分组大小完全相同,恰好为 128 位(16 字节)。输入数据也必须恰好为 128 位。
AES-CTR 算法(CTR 分组密码模式下的 AES)生成的密文与输入数据大小相同,无需填充。
AES-CBC 算法(CBC 分组模式下的 AES)生成的密文大小为 128 位(16 字节)或 128 位的倍数。输入数据应在加密前进行填充,并在解密后去除填充。
AES 算法常与基于密码的密钥派生函数一起使用,例如 Scrypt(passwd) -> key 或 PBKDF2(passwd) -> key。
集成消息认证码(MAC)
AES 算法可以使用 MAC(消息认证码)检查密码是否有效,例如 HMAC(text, key)。
MAC 码通常会集成到算法输出中(参见认证加密概念)。它由输入消息与加密密钥共同计算得出。无法从计算出的 MAC 推导出输入消息或密钥,因此 MAC 本身并非秘密。某些分组密码模式(如 AES-GCM)会在工作过程中将消息认证集成到所得密文中,因此无需显式添加 MAC。
通常按如下方式计算和使用 MAC:
- 加密前,按如下方式计算 MAC:
mac = HMAC-SHA256(input_msg, key)。 - 对输入数据进行加密,并将密文与随机盐(IV)及 MAC 一同保存。
- 解密后,再次计算 MAC,并将其与随加密消息保存的 MAC 进行比较。
- 如果 MAC 相同,则解密成功:密文、解密密钥及算法设置(IV、分组模式、填充算法)均正确。
- 如果 MAC 不同,则解密失败:密钥/密码不正确,或密文损坏、MAC 不正确,或算法设置(IV、分组模式、填充等)不同。
可以使用多种认证加密方法来计算和验证 MAC:先加密后 MAC、加密并 MAC、先 MAC 后加密。
AES 加密过程
完整的 AES 加密过程(基于密码的认证加密)如下:
- 选择算法参数(例如 AES、128 位、CTR 模式 + Scrypt + Scrypt 参数 + MAC 算法)。这些参数可以硬编码在 AES 算法实现的源代码中,也可以作为 AES 加密和解密的输入指定。加密与解密始终应使用相同的参数。
使用密钥派生函数(KDF,如带特定参数的 Scrypt),从加密密码派生出加密密钥:

AES 加密方案以输入消息 + 加密密钥作为输入,输出密文 + 随机生成的 IV(128 位盐)+ MAC 码:

- 对于认证加密(如 AES-GCM),AES 加密过程会自动计算 MAC。
如果加密方案不是认证加密(如 AES-CTR),AES 加密过程不会自动计算 MAC,需要额外计算。可以使用加密密钥(或其某种变换)和某个 MAC 函数(如 HMAC-SHA-256),根据输入消息计算 MAC 码:

密文由 AES 加密算法计算得到。算法首先生成随机盐(IV),然后在 AES 密码的加密逻辑中,使用该盐和加密密钥变换输入消息:

- 最后生成加密输出,其中包含密文 + IV + MAC,还可以选择包含算法设置。
AES 解密过程
与之相反的 AES 解密过程(基于密码的认证解密)如下:
- 为解密过程初始化与加密时完全相同的 AES 算法参数。
使用解密密钥和加密消息中的 IV,通过 AES 算法的解密逻辑解密密文。输出为原始消息(先前经过 AES 加密的输入消息):

- 对于认证加密(如 AES-GCM),解密过程中会验证集成的 MAC 码。
- 对于非认证加密(如 AES-CTR),需要按照接下来的几个步骤额外计算并验证 MAC 码。
计算解密所得原始消息的 HMAC:

比较加密 MAC(加密前输入消息的 MAC)与解密 MAC(解密恢复出的原始消息的 MAC):

- 如果 MAC 码相同,说明解密正确,已获得原始消息。
- 如果 MAC 码不同,说明解密失败,所得消息并非原始消息。出现这种情况的原因很多,最可能是“密码错误”。其他原因包括:密文不正确、IV 不正确、算法设置不正确、KDF 函数或 KDF 参数不正确等。
现在通过可运行的源代码来演示上述概念:使用给定密码对输入消息执行 AES 加密/解密。