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

使用 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中尝试过这样做,直接的答案是否定的。但是,对于为什么使用 RFC 类而不使用我上面提到的其他替代方案,你们是否得到了一个更有根据的答案?

55184 次浏览

您真的真的不希望将用户密码直接用作加密密钥 尤其是和 AES。

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

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

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

多次迭代(默认为1000次)减慢了密码猜测攻击。考虑某人试图猜测您的 AES 密钥。如果您只是使用密码,那么这很简单——只需尝试每个可能的密码作为密钥。另一方面,对于 PBKDF2,攻击者首先必须执行1000次哈希迭代来猜测 每个人的密码。因此,虽然它只是稍微减慢了用户的速度,但它对攻击者有着不成比例的影响。(事实上,使用更高的迭代次数是很常见的; 通常推荐使用10000)。

这也意味着最终的输出键是均匀分布的。例如,如果使用密码,密钥的128位中通常有16位是0(高 ASCII 位)。即使忽略密码猜测,键盘搜索65536也会比应该的要容易很多。

最后,AES 对于相关的密钥攻击具有特定的漏洞。当攻击者知道某些数据是用几个密钥加密的,并且它们之间存在某种已知(或猜测的)关系时,就可能发生相关的密钥攻击。例如,如果你加密数据的密码都是“我的 AES 钥匙吸”(16字节,为 AES-128)和“我的 AES 钥匙吸”,一个相关的密钥攻击可能是可能的。目前最著名的攻击实际上并不允许以这种方式破解完整的 AES,但是随着时间的推移,它们已经变得越来越好了——就在上周,一个新的攻击发布了,使用一个相关的密钥攻击破解了13轮(总共14轮)的 AES-256。如果指望这种攻击不会随着时间的推移而得到改善,那将是极其不明智的。