为什么我需要使用Rfc2898DeriveBytes类(在.NET中)而不是直接将密码用作密钥或IV?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (61)

使用Rfc2898DeriveBytes和只使用它有Encoding.ASCII.GetBytes(string object);什么区别?

我在任何一种方法方面都取得了相对的成功,前者是一种更为冗长的方法,后者简单而重要。两者似乎都允许你最终做同样的事情,但我正在努力使用前者而不是后者。

我已经能够掌握的基本概念是,您可以将字符串密码转换为字节数组,以用于例如对称加密类AesManaged。通过RFC类,但在创建rfc对象时可以使用salt值和密码。我认为它更安全,但仍然是一个没有受过教育的猜测!此外,它允许你返回一定大小的字节数组,就像那样。

以下是一些示例,展示我来自哪里:

byte[] myPassinBytes = Encoding.ASCII.GetBytes("some password");

要么

string password = "P@%5w0r]>";
byte[] saltArray = Encoding.ASCII.GetBytes("this is my salt");
Rfc2898DeriveBytes rfcKey = new Rfc2898DeriveBytes(password, saltArray);

'rfcKey'对象现在可用于在对称加密算法类中设置.Key或.IV属性。

即。

RijndaelManaged rj = new RijndaelManaged ();
rj.Key = rfcKey.Getbytes(rj.KeySize / 8); 
rj.IV = rfcKey.Getbytes(rj.Blocksize / 8);

'rj'应该准备好了!

令人困惑的部分...所以不是使用'rfcKey'对象,我可以不使用我的'myPassInBytes'数组来帮助设置我的'rj'对象?

我已经尝试在VS2008中做这个,直接的答案是NO。但是你们有没有更好的教育方面的答案,为什么RFC类被用于上面提到的其他替代方案?

提问于
用户回答回答于

你真的,真的不想直接使用用户密码作为加密密钥,尤其是使用AES。

Rfc2898DeriveBytes是PBKDF2的一个实现。它所做的是重复散列用户密码和salt。这有多个好处:

首先,可以使用任意大小的密码 - AES仅支持特定的密钥大小。

其次,盐的加入意味着你可以使用相同的密码来生成多个不同的键(假设salt不是一个常量,就像你的例子中那样)。这对于关键分离很重要; 在不同的上下文中重用密钥是加密系统破坏的最常见方式之一。

多次迭代(默认为1000)减缓了密码猜测攻击。考虑一个试图猜测你的AES密钥的人。如果你只是使用密码,这将是直截了当的 - 只要尝试每个可能的密码作为关键。另一方面,对于PBKDF2,攻击者首先必须对每个密码猜测执行1000次散列迭代。所以虽然它只会稍微减慢用户速度,但对攻击者却有不成比例的影响。(事实上​​,使用更高的迭代次数是相当常见的;通常建议使用10000次)。

这也意味着最终的输出密钥是均匀分布的。例如,如果您使用密码,则密钥的128位中的16位通常为0(高位ASCII位)。那就在那里,立即使密钥搜索比应该更容易65536倍,甚至忽略密码猜测。

最后,AES与相关的关键攻击存在特定的漏洞。当攻击者知道用几个密钥加密的数据时,相关的密钥攻击是可能的,并且他们之间有一些已知(或猜测)的关系。例如,如果使用“我的AES密钥吮吸”(16字节,对于AES-128)和“我的AES密钥攫取”的密码密钥对数据进行加密,则可能会发生相关的密钥攻击。目前最为人所知的攻击实际上并不允许以这种方式破坏完整的AES,但随着时间的推移,它们逐渐变得越来越好 - 就在上周发布了一个新的攻击,该攻击使用AES-256中的13轮(共14个)一个相关的关键攻击。依靠这种攻击不会随着时间的推移变得越来越不明智。

用户回答回答于

简答:更安全。出于同样的原因,System.Security命名空间中还有一个特殊的随机生成器。

有关详细信息,请参阅RFC2898

我明白一点:

使用Encoding.ASCII.GetBytes(),当你使用一个长密码时,你至多会使用它的第一个rj.KeySize字节。其余的被忽略。而当你的密码比密钥长度短时,你将不得不添加填充(并且只是增加一个0的增加漏洞序列)。

扫码关注云+社区