使用OpenSSL AESNI汇编函数时aes_cbc_encrypt()解密异常求助
AES-NI CBC加解密结果错误的原因与修复
你的测试代码解密结果不正确,核心问题是CBC模式加密过程会修改传入的IV缓冲区,而你解密时误用了被修改后的IV。另外还有几个需要注意的细节:
核心问题:IV被加密函数修改
aesni_cbc_encrypt在加密模式下,每处理完一个数据块后,会自动将IV更新为当前的密文块(这是CBC模式的流程要求)。你在加密后直接使用同一个IV变量进行解密,此时IV已经不是原始值,导致解密逻辑错误。
修复步骤
- 备份原始IV:在加密前复制一份原始IV,解密时使用备份的IV。
- 确保密钥初始化正确:
aesni_set_decrypt_key需要正确初始化解密用的轮密钥结构,你的代码中已调用该函数,只要函数实现正常即可。
修正后的测试代码:
#include <stdio.h> #include <string.h> #include <openssl/aes.h> int aesni_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); int aesni_set_decrypt_key(const unsigned char *userKey, int bits, AES_KEY *key); void aesni_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, int enc); int main() { int i; unsigned char key[] = "\xE0\xE6\x0C\x86\xF1\x10\xF5\x3A\x4E\x65\x88\x79\x74\xB1\x4E\x3D\x06\x22\x9D\xB9\x4E\x26\x25\xBE\xD1\x18\x2B\x56\x73\xAB\x44\xF3"; unsigned char iv[] = "\x06\x22\x9D\xB9\x4E\x26\x25\xBE\xD1\x18\x2B\x56\x73\xAB\x44\xF3"; unsigned char original_iv[16]; memcpy(original_iv, iv, 16); // 备份原始IV unsigned char in[] = "\x64\x6f\x20\x77\x68\x61\x74\x63\x68\x61\x20\x68\x61\x66\x74\x61"; unsigned char out[16]; unsigned char tmp[16]; // 打印明文 size_t blksz = 16; for (i=0;i<blksz;i++) printf("%02x ", in[i]); puts(""); AES_KEY ks; aesni_set_encrypt_key(key, 256, &ks); aesni_cbc_encrypt(in, tmp, blksz, &ks, iv, 1); // 加密,此时iv已被修改 // 打印密文 for (i=0;i<blksz;i++) printf("%02x ", tmp[i]); puts(""); // 解密:恢复原始IV memcpy(iv, original_iv, 16); aesni_set_decrypt_key(key, 256, &ks); aesni_cbc_encrypt(tmp, out, blksz, &ks, iv, 0); // 解密 // 打印解密后的明文 for (i=0;i<blksz;i++) printf("%02x ", out[i]); puts(""); return 0; }
额外注意事项
- 直接调用OpenSSL的内部汇编函数(如
aesni_*系列)没有官方API兼容性承诺,OpenSSL版本升级可能会改变这些函数的签名或内部逻辑,生产环境使用需谨慎。 - 若处理多块数据,CBC模式要求明文长度必须是AES块大小(16字节)的倍数,不足时需要添加填充(如PKCS#7),你的测试数据刚好是16字节,所以无需处理。
内容的提问来源于stack exchange,提问作者shawnixer
相关产品推荐
相关产品推荐

