如果salt是随机的,那么从密码(和密钥一样)导出初始化向量可以吗



密码大师请提供帮助。

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

现在我认为,如果我使用随机salt,随机生成IV是多余的,因为我可以从带有该salt的密码字符串中导出密钥和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);
}

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

请注意,如果你的一位同事认为PasswordDeriveBytes(微软PBKDF1的坏实现)更适合执行这项任务,那么你很可能很容易受到各种攻击。这只是一个例子,如果你的安全边际很紧,可能会出错。。。

完全随机静脉注射当然是首选。

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

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

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

使用Rfc2898DeriveBytes生成密钥,并使用良好的加密RNG生成IV。请记住,攻击者会看到IV,因此无需经过完整的RFC 2898过程。使用IV的标准加密RNG,这可能比RFC 2898过程更快,因为它没有迭代。

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

在您建议的实现中,给定的密钥将始终具有相同的初始化向量,但由于您的128位salt,您不会使用相同的密钥。这似乎很不可预测,也就是说,这不是一个最佳实践,通常当你做一些聪明的事情来节省16字节的空间时,你会失去一些安全性,或者向一些未知的攻击向量开放。

我认为你应该使用RNG并获得16字节的空间命中率,在处理加密时,保守是游戏的名称。还有其他事情,比如身份验证加密,你可能也应该研究一下,我有一个关于代码审查的示例实现。

最终,除了iv之外,还有其他重要的东西为安全性提供了额外的开销,如身份验证加密、版本控制和密钥轮换,而且实际上还没有任何针对C#的高级加密框架。我一直致力于谷歌Keyczar框架的C#实现。如果你愿意,你可以在github Keyczar网络上关注它。它的功能非常完整,测试覆盖率达到90%,但保守地说,我不建议使用它,直到它被正式接受为项目的一部分,然后在未来可能会有更多的人关注它。

最新更新