是否可以从密码中获取初始化向量(与密钥一样),因为盐将是随机的?

时间:2012-09-27 11:24:17

标签: c# java encryption cryptography

密码专家请帮帮忙。

我已经了解到,使用对称算法(例如AES)的加密密钥应该通过PBKDF2函数从密码派生,使用每个加密中的随机盐。我还了解到IV不应该是硬编码的,也不应该直接绑定到(派生自)密码字符串或加密密钥。到目前为止,我随机生成两个密钥派生盐 IV,每个16字节用于我的AES-256加密,并将它们与加密的有效负载一起存储。

现在我认为随机生成IV是多余的,如果我使用随机盐,因为我可以从密码字符串中获取密钥和IV。或许我不应该?

所以我的问题最终是这样的:

我可以从密码中获取初始化向量(就像我使用密钥一样),或者我应该每次生成随机IV,因为我在每次加密时都使用随机盐吗?

我可以使用下面的C#代码吗?

// Derive key and initialization vector from password:

// ---> NOTE: _salt is random 16 bytes in each encryption.

byte[] key, iv;

using (Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(password, _salt, _iterations))
{
    key = derivedBytes.GetBytes(32);
    iv = derivedBytes.GetBytes(16);
}

4 个答案:

答案 0 :(得分:3)

是的,你可以这样使用它,只要你从来没有使用相同的盐用于相同的密码(即使在时间上)来计算密钥和IV。当您使用相同的密钥加密时,IV只需要是唯一的,并且您每次都会计算一个新密钥。原则上你甚至可以使用全零IV,因为密钥永远不会重复,但你最好使用派生的。

请注意,如果您的某位同事决定PasswordDeriveBytes - 来自Microsoft的PBKDF1的破坏实施 - 将更适合该任务,那么您很可能容易受到各种攻击。这只是一个例子,如果您的安全边际紧张,可能会出错......

完全随机的IV应该是首选。

答案 1 :(得分:0)

你是说“在每次加密中使用随机盐”是什么意思?最好随机导出salt和IV,例如加密标准随机数生成器的输出,并将其与派生字节一起存储。为每个密码生成一个新的IV和salt。

为什么使用加密标准RNG?从密码派生意味着派生字节函数中的任何弱点都反映在字节和IV中。在现代编程语言中,从RNG生成它并使用RNG确保加密的新密码的IV是不可预测的并不困难。可能有更好的理由,但我画的是空白。

答案 2 :(得分:0)

任何加密系统的不同部分之间的链接越多,任何攻击者都越容易将这些链接用作从系统的一个部分到另一个部分的后门。请记住,IV是以明文发送的,而密钥必须保密,因此它们之间的任何类型的链接都是一个很大的风险。

使用Rfc2898DeriveBytes生成密钥并使用一个好的加密RNG来生成IV。请记住,攻击者将看到IV,因此无需完成整个RFC 2898流程。使用标准加密RNG用于IV可能比RFC 2898进程更快,因为它没有迭代。

答案 3 :(得分:0)

使用AES-CBC时初始化向量的语义安全性最重要的部分是它不应该是可预测的。

根据您建议的实现,给定的键将始终具有相同的初始化向量,但由于您的128位盐,您将不会使用相同的键。似乎很不可预测,这说,这不是一种最佳做法,通常当你做一些聪明的事情来节省16个字节的空间时,你会失去一些某种安全性或者让自己打开一些未知的攻击向量。

我认为你应该使用RNG并占用空格16字节,保守是处理加密时游戏的名称。还有其他一些事情,例如您应该查看的身份验证加密,我有一个example implementation on codereview

最终还有其他一些重要的东西,除了iv之外还提供了额外的开销,例如经过身份验证的加密,版本控制和密钥旋转,并且确实没有任何针对C#的高级加密框架。我一直在研究Google的Keyczar框架的C#实现。如果您愿意,可以在github Keyczar-dotnet上关注它。它的功能非常齐全,并且有90%的测试覆盖率,但保守地说,我不建议在它被正式接受为项目的一部分之前使用它,然后将来可能会有更多的眼睛。