如何使用 OpenSSL 进行 AES 解密

Posted

技术标签:

【中文标题】如何使用 OpenSSL 进行 AES 解密【英文标题】:How to do AES decryption using OpenSSL 【发布时间】:2011-07-05 05:06:37 【问题描述】:

我想使用 OpenSSL 库来解密一些 AES 数据。代码可以访问密钥。这个项目已经将 libopenssl 用于其他用途,所以我想坚持使用这个库。

我直接查看了/usr/include/openssl/aes.h,因为 OpenSSL 站点的文档很少。唯一的解密函数就是这个:

void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);

不幸的是,这没有办法指定 in 指针的长度,所以我不确定它是如何工作的。

我认为还有其他几个函数需要一个数字参数来区分加密和解密。例如:

void AES_ecb_encrypt(*in, *out, *key, enc);
void AES_cbc_encrypt(*in, *out, length, *key, *ivec, enc);
void AES_cfb128_encrypt(*in, *out, length, *key, *ivec, *num, enc);
void AES_cfb1_encrypt(*in, *out, length, *key, *ivec, *num, enc);
void AES_cfb8_encrypt(*in, *out, length, *key, *ivec, *num, enc);
void AES_cfbr_encrypt_block(*in, *out, nbits, *key, *ivec, enc);
void AES_ofb128_encrypt(*in, *out, length, *key, *ivec, *num);
void AES_ctr128_encrypt(*in, *out, length, *key, ivec[], ecount_buf[], *num);
void AES_ige_encrypt(*in, *out, length, *key, *ivec, enc);
void AES_bi_ige_encrypt(*in, *out, length, *key, *key2, *ivec, enc);

根据我使用 Google 的理解,enc 参数设置为 AES_ENCRYPTAES_DECRYPT 以指定需要执行的操作。

这让我想到了两个问题:

    这些名称是什么意思?什么是 ecb、cbc、cfb128 等...,我该如何决定应该使用哪一个? 其中大多数所需的 unsigned char *ivec 参数是什么,我从哪里获得它?

【问题讨论】:

你应该使用AES_encrypt和朋友。您应该使用EVP_* 函数。请参阅 OpenSSL wiki 上的 EVP Symmetric Encryption and Decryption。事实上,您可能应该使用经过身份验证的加密,因为它提供 机密性和真实性。请参阅 OpenSSL wiki 上的 EVP Authenticated Encryption and Decryption。 【参考方案1】:

没有给出大小,因为 AES 的块大小是固定的基于密钥大小;你发现ECB模式实现,不适合直接使用(除了作为教学工具)。

ECB、CBC、CFB128 等都是常用的modes of operation 的简称。它们有不同的属性,但如果你从不接触 ECB 模式,你应该没问题。

我建议远离低级代码;如果可以,请改用EVP_* 接口,并且您可以将其中一些决策移至文本配置文件中,这样您的用户就可以轻松地在不同的密码、块大小和操作模式之间进行选择(如果应该有)改变默认设置的好理由。

我的同情,OpenSSL 文档感觉比现在更糟,而且不是那么好。您可能会发现Network Security with OpenSSL 是一本有用的书。我希望我上次需要使用 OpenSSL 时能早点找到它。 (不要让愚蠢的标题欺骗了你——它应该被命名为“OpenSSL”。哦,好吧。)

编辑我忘了提到initialization vectors。它们用于确保如果您使用相同的密钥加密相同的数据,密文将不会相同。您需要 IV 来解密数据,但您不需要对 IV 保密。您应该为每个会话随机生成一个(并将其与 RSA 或 El Gamal 或 DH 加密的会话密钥一起发送)或在两个端点上生成相同的,或将其与文件一起存储在本地,类似这样。

【讨论】:

“没有给出大小,因为 AES 的块大小是根据密钥大小固定的”——不是真的;它们固定为 16 个字节,与密钥大小无关。而AES_decrypt之所以不占用大小是因为它只解密一个块,所以长度固定为16。 请注意,如果您正在解密由您无法控制的另一个进程加密的消息,则该进程将指定块密码模式(CBC、CFB 等)。初始化向量应与密文一起提供。 请注意,Java 在被告知使用 AES 而不指定任何其他内容时,默认为 ECB 模式。一旦我了解了这一点以及所有这些功能的用途,事情就变得更有意义了。现在我的 C/C++ 代码使用 OpenSSL 来解密来自这个特定 Java 应用程序的有效负载。 @Stéphane,可惜 Java 默认为 ECB 模式,它确实不适合“最终用户”,但它最低公分母。 @sarnold:如何使用 EVP_* 接口进行 AES 加密?在您链接到的页面上,我看到了许多密码,但没有看到 AES。

以上是关于如何使用 OpenSSL 进行 AES 解密的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中解密 OpenSSL AES 加密的文件?

PHP如何使用AES加密和解密

使用OpenSSL进行AES-256 / CBC加密并使用C#进行解密

java加密用PHP解密

PHP的aes加解密算法

c语言中的openssl aes解密