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

Ibr*_*taz 72 c# cryptography rfc2898

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

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

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

以下是一些示例,向您展示我的来源:

byte[] myPassinBytes = Encoding.ASCII.GetBytes("some password");
Run Code Online (Sandbox Code Playgroud)

要么

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

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

即.

RijndaelManaged rj = new RijndaelManaged ();
rj.Key = rfcKey.Getbytes(rj.KeySize / 8); 
rj.IV = rfcKey.Getbytes(rj.Blocksize / 8);
Run Code Online (Sandbox Code Playgroud)

'rj'应该准备好了!

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

我试过在VS2008中这样做,直接答案是否定的.但是,你们有一个更好的教育答案,为什么RFC类被用于上面提到的另一种选择?

Jac*_*oyd 171

你真的,真的不想直接使用用户密码作为加密密钥,特别是使用AES.

Rfc2898DeriveBytes是PBKDF2的实现.它的作用是反复哈希用户密码和盐.这有很多好处:

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

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

多次迭代(默认为1000次)减慢了密码猜测攻击.考虑一下试图猜测您的AES密钥的人.如果你刚刚使用了密码,这将是直截了当的 - 只需尝试每个可能的密码作为密钥.另一方面,对于PBKDF2,攻击者首先必须为每个密码猜测执行1000次哈希迭代.因此,虽然它只是略微降低了用户的速度,但它对攻击者产生了不成比例的影响.(事实上​​,使用更高的迭代次数是很常见的;通常建议使用10000次).

它还意味着最终输出键是均匀分布的.例如,如果使用密码,通常密钥的128位中的16位将为0(高位ASCII).在那里立即使keysearch比它应该容易65536倍,甚至忽略密码猜测.

最后,AES具有针对相关密钥攻击的特定漏洞.当攻击者知道使用多个密钥加密的某些数据时,相关的密钥攻击是可能的,并且它们之间存在一些已知(或猜测)的关系.例如,如果您使用密码密钥"My AES key sucks"(16字节,对于AES-128)和"MY AES KEY SUCKS"加密数据,则可能会发生相关的密钥攻击.目前最着名的攻击实际上不允许以这种方式打破完整的AES,但随着时间的推移它们逐渐变得越来越好 - 就在上周发布了一个新的攻击,它突破了使用AES-256的13轮(总共14轮)相关的关键攻击.依靠此类攻击随着时间的推移不会变得更好是非常不明智的.