AES_CBC块加密实现踩坑记录
块加密
💡 主要实现
- ✅ 支持 Encrypt-Then-MAC(ETM)& Mac-Then-Encrypt (MTE)。
- ✅ 支持 MAC-Then-Encrypt(标准 TLS 1.2)。
- ✅ 根据加密套件进行块加密。
- ✅ 使用加密套件中的哈希算法计算 MAC。
🔹 encrypt_record()
流程
- 生成 随机 IV。
- 计算 HMAC-sha256(根据 TLS 1.2 记录层规则)以HMAC-sha256为例
- AES-CBC 加密(包含 MAC & 填充) 以AES-CBC为例。
- 返回 完整的 TLS 记录 (IV + Ciphertext)。
🔹 decrypt_record()
流程
- 解析 IV(显式 IV)。
- AES-CBC 解密(去掉填充)。
- 验证 HMAC,确保完整性。
- 返回 解密后的明文。
🔍计算HMAC
HMAC计算的输入结构如下
AuthenticatedMetaData[seq_num (8B) + ContentType (1B) + TLSVersion (2B) + Length (2B) ]+ AuthenticatedNoMetaData[Finished 明文 (16B)]
输出长度应该跟MAC_Key长度一致
MAC[mac_key_len]
- seq_num (8B) :当前 TLS 记录的序列号,从 0 开始,每发送一个记录增加 1。
- ContentType (1B) :Finished 消息的 ContentType 为 0x16(Handshake)。
- TLSVersion (2B) :TLS 1.2 版本,值为 0x0303。
- Length (2B) :Finished 消息的明文长度,值为 0x000C(12)。
- Plaintext (16B) :即 Finished消息
📌AES 块加密
AES加密的输入:
plaintext = data + MAC + Padding
要求保证plaintext的长度时块的倍数
/*
*
* 注意 仅适用于需要 PKCS#7 的模式(如 AES-CBC、AES-ECB)
* 不适用于 AES-GCM、AES-CCM(AEAD 模式不需要填充)。
*/
//RFC5246 定义块加密明文结构如下
struct {
opaque IV[SecurityParameters.record_iv_length];
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length; !!!!
};
} GenericBlockCipher;
根据RFC5246 中描述, 实际的数据要多一位,多一个padding_length
而在openssl服务端处理计算Context长度时:
代码如下:
aesni_cbc_encrypt(in, out, len, &ctx->ks, ctx->base.iv, 0);
//figure out payload length
pad = out[len - 1];
inp_len = len - (SHA_DIGEST_LENGTH + pad + 1);
:SHA_DIGEST_LENGTH = MAC_len
所以如果我们这里应该填充Padding_length-1
正好使得计算的inp_len
正确,
否则会导致计算MAC失败
✅ 如何确认使用的哈希算法?
在 ClientHello / ServerHello 握手 过程中,服务器和客户端会协商一个 CipherSuite,其中会指明 HMAC 的哈希算法。例如:
CipherSuite | 密钥交换算法 | 对称加密算法 | MAC(HMAC 哈希)算法 |
---|---|---|---|
TLS_RSA_WITH_AES_128_CBC_SHA |
RSA | AES-128-CBC | SHA-1 |
TLS_RSA_WITH_AES_128_CBC_SHA256 |
RSA | AES-128-CBC | SHA-256 |
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 |
DHE + RSA | AES-256-GCM | SHA-384 |
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 |
ECDHE + RSA | AES-128-GCM | SHA-256 |
所以,最终的 HMAC 哈希算法是由 CipherSuite 选择的。
MAC | Algorithm | mac_length | mac_key_length |
---|---|---|---|
NULL | N/A | 0 | 0 |
MD5 | HMAC-MD5 | 16 | 16 |
SHA | HMAC-SHA1 | 20 | 20 |
SHA256 | HMAC-SHA256 | 32 | 32 |
验证加密结果是否正确
# 1. 生成填充后的明文二进制文件
echo "1400000C0117E62EBD66175B27F52831E24C395647FEB439288B9D27C4B92BAF55928D350B0B0B0B0B0B0B0B0B0B0B0B10101010101010101010101010101010" | xxd -r -p > padded.bin
# 执行AES-128-CBC加密
openssl enc -aes-128-cbc -nosalt \
-K B7B77162CBF57D2A280CD9E77832877A \
-iv 93578CFC6863B968A97327948D368FC1 \
-in padded.bin -out encrypted.bin
# 查看加密结果(Hex格式)
xxd -p encrypted.bin | tr -d '\n'