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

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

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

我已经能够掌握的基本概念是,可以将string密码转换为字节数组,以用于例如对称encryption类AesManaged 。 通过RFC类,但你创build你的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'对象来设置对称encryptionalgorithm类中的.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类被用于我上面提到的其他替代scheme?

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

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

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

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

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

这也意味着最终的输出密钥是均匀分布的。 例如,如果您使用密码,密钥的128位中的16位通常是0(高位ASCII)。 那就在那里马上使得search65536次比应该更容易,甚至忽略了密码猜测。

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

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

有关详细信息,请参阅RFC2898

我理解一小部分:

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