练习:AES 加密/解密
本练习将使用对称密码 AES-256-CBC,结合 Scrypt 密钥派生和 HMAC 消息认证码,对文本消息进行加密和解密。实际上,我们将实现一个基于密码的对称认证加密方案。
对称加密(AES + Scrypt + HMAC)
编写程序,使用给定密码对文本消息进行加密。按以下步骤进行:
- 使用带随机盐(128 位)的 Scrypt(n=16384, r=16, p=1),从密码派生一个 512 位密钥。
- 将派生密钥拆分为两个 256 位子密钥:加密密钥和 HMAC 密钥。
- 使用 PKCS7 算法填充输入消息,使其长度成为 16 字节(128 位)的倍数。
- 使用加密密钥,通过 AES-256-CBC 加密填充后的消息。所得结果为密文,其长度应为 16 字节(128 位)的倍数,即 AES 密码的分组大小。
- 使用随机生成的 128 位初始化向量(IV)。
- 使用 HMAC-SHA256(hmac_key、ciphertext)计算消息认证码(MAC)。
输入:消息 + 密码(以空格分隔)。
输出:包含以下内容的 JSON 文档(参见下例):
- Scrypt 随机生成的 salt(十六进制格式)。
- AES 密码使用的随机生成 iv(十六进制格式)。
- AES 密码生成的加密消息 ciphertext(十六进制格式)。
- 消息认证码 mac(十六进制格式)。
使用你选择的编程语言编写代码。
| 输入 | 输出 |
|---|---|
| p@sSw0rd~123 SecretMsg | {"salt": "9757a3a22a9937ca0e0f2b5f2a4a11b4", "iv": "2ce8c035d50f7a6ee6509c14fe11725a", "ciphertext": "bb435d8ad048c240b50f0e4a191605d9", "mac": "02cf870ad1f7453c339dac06edbd648c455f5e8abbf6f2716cbc2d164b644200"} |
| stupid!pass longer-message-for-encryption | {"salt": "b243f0ac10ef358ff0d37f1e30ef19c2", "iv": "fdeff97e89705289d99751f079e2a308", "ciphertext": "ea76bc60799c5824627a8c1276b48ab70e24011b6654f8ffb019a4f6876485af", "mac": "34085e1a47ae53e154b7466336efee386c2f1ed61a0105183ef016af794da58f"} |
请注意,由于 salt 和 iv 是随机生成的,你得到的上述输出会有所不同。
对称解密(AES + Scrypt + HMAC)
编写程序,使用给定密码对作为输入的加密消息进行解密。
- 使用 JSON 中的盐和 Scrypt(n=16384, r=16, p=1),从密码派生一个 512 位密钥。
- 将派生密钥拆分为两个 256 位子密钥:加密密钥和 HMAC 密钥。
- 使用 HMAC-SHA256(hmac_key、ciphertext)计算消息认证码(MAC)。
- 将该 MAC 与 JSON 文档中的 MAC 进行比较。
- MAC 相同表示“密码正确/解密成功”。
- MAC 不同表示“密码错误/输入数据不正确”。
- 使用加密密钥和 JSON 中的 IV,通过 AES-256-CBC 解密输入中的密文。
- 使用 PKCS7 算法对解密消息去除填充,将其从 16 字节(128 位)的倍数还原到原始长度(通常更短)。
输入:密码 + JSON(以空格分隔)。JSON 的格式与上一练习的输出完全相同(包含 salt、iv、ciphertext 和 mac,均为十六进制数)。
输出:Decrypted: + 原始解密消息;如果密码错误或发生其他问题,则输出文本 Decryption failed!。
使用你选择的编程语言编写代码。
| 输入 | 输出 |
|---|---|
| p@sSw0rd~123 {"salt": "9757a3a22a9937ca0e0f2b5f2a4a11b4", "iv": "2ce8c035d50f7a6ee6509c14fe11725a", "ciphertext": "bb435d8ad048c240b50f0e4a191605d9", "mac": "02cf870ad1f7453c339dac06edbd648c455f5e8abbf6f2716cbc2d164b644200"} | Decrypted: SecretMsg |
| wrong!pass {"salt": "9757a3a22a9937ca0e0f2b5f2a4a11b4", "iv": "2ce8c035d50f7a6ee6509c14fe11725a", "ciphertext": "bb435d8ad048c240b50f0e4a191605d9", "mac": "02cf870ad1f7453c339dac06edbd648c455f5e8abbf6f2716cbc2d164b644200"} | Decryption failed! |