问题 使用aes_256_cbc密码加密时的默认IV是多少?


我在一个文件中生成了一个随机的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是否意味着“使用默认值”?是否为默认值,并且没有任何内容添加到第一个密码块?

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


9792
2018-06-30 13:54


起源

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


答案:


使用EVP_aes_256_cbc()[sic]密码加密时的默认IV是多少?

  为该参数传递nullptr是否意味着“使用默认值”?是否为默认值,并且没有任何内容添加到第一个密码块?

空无一人。你必须提供它。为了完整起见,IV应该是不可预测的。

不可预测的 与两者略有不同 独特 和 随机。例如,SSLv3过去常常使用最后一个密文块作为下一个块的IV。它是 独特,但它既不是 随机 也不 不可预测的,这使得SSLv3容易受到选择的明文攻击。

其他库做一些聪明的事情,比如提供一个空向量(一个0的字符串)。他们的攻击者感谢他们。另见 为什么使用具有CBC模式的非随机IV是一个漏洞? 在Stack Overflow和 如果使用已知和/或固定的IV,CBC模式下的AES是否安全? 在Crypto.SE上。


/usr/bin/openssl enc -aes-256-cbc...

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

OpenSSL使用内部mashup /密钥派生函数来获取密码,并导出密钥和iv。它叫 EVP_BytesToKey,您可以在手册页中阅读它。该手册页还说:

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

有很多例子 EVP_BytesToKey 一旦你知道要寻找什么。 密钥的Openssl密码 是一个在C. 如何解密使用AES使用openssl命令加密的Java文件 在Java中的一个。


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

  加密时我没有指定IV,因此必须使用一些默认值。

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

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


7
2018-06-30 15:43



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


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

   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.

“哈希”这里是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___ 标题,然后使用salt来计算密钥和IV。然后你就可以把它们分成几部分了 EVP_DecryptInit_ex

既然你在C ++中这样做,你可能只是深入研究 enc 代码并重复使用(在验证其许可证与您的使用兼容之后)。

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

有可能以这种方式使用MD5以泄漏信息的方式缠绕密钥和IV,但我从未见过声称这种情况的分析。如果你必须使用OpenSSL格式,我对它的第四代不会有任何犹豫。 OpenSSL格式存在的主要问题是它蛮力(4轮MD5拉伸不够)并且缺乏任何身份验证。


5
2018-06-30 14:37



呃伙计,你有源代码,你称之为逆向工程? - Pacerier
知道aes 256如何使用256位IV吗?我的理解是IV需要128位而密钥256位。在上面的伪中,两者都是256位正确的。 - Aaron
@Aaron更新。 256位IV是错误的。它工作正常,因为我正在使用的库,但实际上只使用了前128位。 - Rob Napier