使用 aes_256_cbc 密码加密时的默认 IV 是啥?

Posted

技术标签:

【中文标题】使用 aes_256_cbc 密码加密时的默认 IV 是啥?【英文标题】:What is the default IV when encrypting with aes_256_cbc cipher?使用 aes_256_cbc 密码加密时的默认 IV 是什么? 【发布时间】:2016-11-02 16:13:23 【问题描述】:

我在一个文件中生成了一个随机的 256 位对称密钥,用于使用 OpenSSL 命令行加密一些数据,稍后我需要使用 OpenSSL 库以编程方式对其进行解密。我没有成功,我认为问题可能出在我正在使用(或未使用)的初始化向量中。

我使用这个命令加密数据:

/usr/bin/openssl enc -aes-256-cbc -salt -in input_filename -out output_filename -pass file:keyfile

我正在使用以下调用来初始化数据的解密:

EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, keyfile.data(), nullptr))

keyfile 是一个 vector<unsigned char>,它保存了 32 个字节的密钥。我的问题是关于最后一个参数。它应该是密码算法的初始化向量。加密时我没有指定 IV,所以必须使用一些默认值。

为该参数传递 nullptr 是否意味着“使用默认值”?默认为null,第一个密码块什么都不加?

我应该提一下,我可以在不提供 IV 的情况下从命令行解密。

【问题讨论】:

不使用 IV(或固定默认值)不会严重破坏加密强度吗?据我了解,IV 的重点是确保相同的明文不会生成相同的密文。所以需要有一个 IV,它不需要是秘密的,它只需要对你加密的所有东西都是唯一的。不使用一个(或固定的)听起来是个非常糟糕的主意。 我不是密码学家,也没有在电视上玩过密码,所以我真的没有资格回答(因此为什么上面只是一个评论)。作为一个非专家我会只要密钥每次都是唯一的那么它可能没问题,但是作为一个知道他对加密知之甚少的实用主义者我可能会使用随机IV 也是,无论如何,并将其与加密数据一起存储。 我找到了一些相关信息:Answer on crypto.stackexchange.com Regarding using the same IV with different keys for each plaintext. 那里接受的答案似乎与我最初的直觉一致,即使用固定 IV 会降低强度(在攻击者试图暴力破解密钥的情况下)。因此,即使密钥是唯一的,我也会每次都使用(真正的)随机 IV。 @JesperJuhl - 每种模式通常有不同的要求。 CBC 通常需要不可预测的 IV。我更新了我的答案以提供参考。 【参考方案1】:

EVP_DecryptInit_ex 是 AES 解密原语的接口。这只是解密 OpenSSL 加密格式所需的一部分。 OpenSSL 加密格式没有很好的文档记录,但您可以从代码和一些文档中反向使用它。 EVP_BytesToKey 文档中解释了密钥和 IV 计算:

   The key and IV is derived by concatenating D_1, D_2, etc until enough
   data is available for the key and IV. D_i is defined as:

           D_i = HASH^count(D_(i-1) || data || salt)

   where || denotes concatentaion, D_0 is empty, HASH is the digest
   algorithm in use, HASH^1(data) is simply HASH(data), HASH^2(data) is
   HASH(HASH(data)) and so on.

   The initial bytes are used for the key and the subsequent bytes for the
   IV.

这里的“HASH”是MD5。实际上,这意味着您可以像这样计算哈希:

Hash0 = ''
Hash1 = MD5(Hash0 + Password + Salt)
Hash2 = MD5(Hash1 + Password + Salt)
Hash3 = MD5(Hash2 + Password + Salt)
...

然后提取密钥所需的字节,然后提取 IV 所需的字节。对于 AES-128,这意味着 Hash1 是密钥,Hash2 是 IV。对于 AES-256,键是 Hash1+Hash2(连接,未添加),Hash3 是 IV。

您需要去掉前面的Salted___ 标头,然后使用盐计算密钥和IV。然后你就可以将这些片段输入EVP_DecryptInit_ex

不过,由于您是在 C++ 中执行此操作,因此您可能只需挖掘 enc 代码并重复使用它(在验证其许可证与您的用途兼容之后)。

请注意,OpenSSL IV 是随机生成的,因为它是涉及随机盐的散列过程的输出。第一个区块的安全性不依赖于 IV 本身是随机的;它只要求永远不要重复特定的 IV+Key 对。 OpenSSL 过程确保只要随机盐不会重复。

以这种方式使用 MD5 可能会以泄露信息的方式将密钥和 IV 纠缠在一起,但我从未见过这样的分析。如果你必须使用 OpenSSL 格式,我不会对它的 IV 代有任何犹豫。 OpenSSL 格式的大问题是它的暴力破解速度很快(4 轮 MD5 还不够拉伸),而且它缺乏任何身份验证。

【讨论】:

呃老兄,你有源代码,你称之为逆向工程? 知道 aes 256 如何与 256 位 IV 一起工作吗?我的理解是 IV 需要 128 位和密钥 256 位。在上面的伪代码中,两者都是 256 位正确的。 @Aaron 已更新。 256 位 IV 是错误的。由于我使用的库,它运行良好,但实际上只使用了前 128 位。【参考方案2】:

使用 EVP_aes_256_cbc() [原文如此] 密码加密时的默认 IV 是什么... 为该参数传递 nullptr 是否意味着“使用默认值”?默认为null,第一个密码块什么都不加?

没有。你必须提供它。为了完整起见,IV 应该是不可预测的。

Non-PredictableUniqueRandom 略有不同。例如,SSLv3 曾经将最后一个密文块用于下一个块的 IV。它是唯一的,但它既不是随机的也不是不可预测的,它使 SSLv3 容易受到选择的明文攻击。

其他库做了一些聪明的事情,比如提供一个空向量(一个 0 的字符串)。他们的攻击者为此感谢他们。另请参阅 Stack Overflow 上的 Why is using a Non-Random IV with CBC Mode a vulnerability? 和 Crypto.SE 上的 Is AES in CBC mode secure if a known and/or fixed IV is used?。


/usr/bin/openssl enc -aes-256-cbc... 我应该提一下,我可以在不提供 IV 的情况下从命令行解密。

OpenSSL 使用内部混搭/密钥派生函数,该函数接受密码,并派生密钥和 iv。它称为EVP_BytesToKey,您可以在手册页中了解它。手册页还说:

如果总密钥和 IV 长度小于摘要长度并且使用 MD5,则派生算法与 PKCS#5 v1.5 兼容,否则使用非标准扩展来派生额外数据。

一旦您知道要查找什么,就会有很多EVP_BytesToKey 的示例。 Openssl password to key 在 C 中是一。How to decrypt file in Java encrypted with openssl command using AES 在 Java 中是一。


EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, keyfile.data(), nullptr)) 加密时我没有指定 IV,所以必须使用一些默认值。

检查您的返回值。呼叫应该在路径上的某个地方失败。也许不在EVP_DecryptInit_ex,但肯定在EVP_DecryptFinal之前。

如果没有失败,请提交错误报告。

【讨论】:

直到 EVP_DecryptFinal 才失败。这是很多很好的信息,谢谢!

以上是关于使用 aes_256_cbc 密码加密时的默认 IV 是啥?的主要内容,如果未能解决你的问题,请参考以下文章

启用 TLSv1.2 和 TLS_RSA_WITH_AES_256_CBC_SHA256 密码套件

启用TLSv1.2和TLS_RSA_WITH_AES_256_CBC_SHA256密码套件

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

AES-256-CBC用PHP加密并用Java解密

是否可以禁用云锋网的一些特定密码?

AES (aes-cbc-128, aes-cbc-192, aes-cbc-256) 使用 openssl C 加密/解密