AES-256 CBC模式C语言实现的PKCS#7填充问题排查
AES-256 CBC加密C版本与Python/C#结果不一致的问题解决
现有Python和C#实现的AES-256 CBC模式加密程序,加密输出均为9192D9DACF7E02D06F00DB82DFED3E3764C159683BE158F76D95114288F512EA。但使用Tiny AES库编写的C版本仅前32位输出正确,后半段为无效数据,经排查是PKCS#7填充未正确实现导致的,以下是问题分析及解决方案。
原始Python代码
import os from cryptography.hazmat.primitives.ciphers import (algorithms, modes, Cipher) from cryptography.hazmat.primitives.padding import PKCS7 text = "6bcdax94cvrdnhvo" key = "7copiqupo7cpaq7c9u7qab84rpc16gvk" encodedText = text.encode() encodedKey = key.encode() iv = encodedKey[:16] cipher = Cipher(algorithms.AES(encodedKey), modes.CBC(iv)) encryptor = cipher.encryptor() padder = PKCS7(128).padder() pad = padder.update(encodedText) + padder.finalize() print(encryptor.update(pad))
原始C#代码
using System.Text; using System.Security.Cryptography; string text = "6bcdax94cvrdnhvo"; string key = "7copiqupo7cpaq7c9u7qab84rpc16gvk"; byte[] byteKey= Encoding.ASCII.GetBytes(key); Aes aesAlg = Aes.Create(); aesAlg.Mode = CipherMode.CBC; aesAlg.Key = byteKey; aesAlg.IV = byteKey[0..16]; ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); byte[] encrypted = encryptor.TransformFinalBlock(Encoding.ASCII.GetBytes(text), 0, Encoding.ASCII.GetBytes(text).Length); encryptor.Dispose(); string plainText = BitConverter.ToString(encrypted); plainText = plainText.Replace("-", ""); Console.WriteLine($@"{plainText}");
原始问题C代码
#include <stdint.h> #include "aes.h" int main() { uint8_t text[16] = "6bcdax94cvrdnhvo"; uint8_t key[32] = "7copiqupo7cpaq7c9u7qab84rpc16gvk"; uint8_t iv[16]; int i; for (i = 0; i < 16; i++) { iv[i] = key[i]; } struct AES_ctx ctx; AES_init_ctx_iv(&ctx, key, iv); AES_CBC_encrypt_buffer(&ctx, text, 16); for (i = 0; i < 16; i++) { printf("%.2x", text[i]); } return 0; }
问题分析
- 填充缺失:Python和C#的代码都自动处理了PKCS#7填充(Python显式调用PKCS7填充器,C#的
TransformFinalBlock默认添加PKCS#7填充),而原始C代码完全没有实现填充逻辑。 - 数据长度规则:待加密的明文
"6bcdax94cvrdnhvo"刚好是16字节(AES单块大小),按照PKCS#7规则,此时必须填充一个完整的块(16个0x10字节),否则加密后的结果会少一个块,仅前半段匹配预期输出。
解决方案
在C代码中手动实现PKCS#7填充逻辑,将明文缓冲区扩展为32字节(两个AES块),填充后再执行加密操作。
修正后的C代码
#include <stdint.h> #include <string.h> #include "aes.h" // PKCS#7填充实现 void pkcs7_pad(uint8_t *data, size_t data_len, size_t block_size) { uint8_t pad_len = block_size - (data_len % block_size); memset(data + data_len, pad_len, pad_len); } int main() { // 明文刚好16字节,需填充16字节,缓冲区设为32字节 uint8_t text[32] = "6bcdax94cvrdnhvo"; uint8_t key[32] = "7copiqupo7cpaq7c9u7qab84rpc16gvk"; uint8_t iv[16]; size_t text_len = strlen((char*)text); const size_t block_size = 16; int i; for (i = 0; i < 16; i++) { iv[i] = key[i]; } // 执行PKCS#7填充 pkcs7_pad(text, text_len, block_size); struct AES_ctx ctx; AES_init_ctx_iv(&ctx, key, iv); // 加密32字节数据(两个完整块) AES_CBC_encrypt_buffer(&ctx, text, 32); for (i = 0; i < 32; i++) { printf("%.2x", text[i]); } printf("\n"); return 0; }
内容的提问来源于stack exchange,提问作者MrWicked
相关产品推荐
相关产品推荐

