C# 为什么RijndaelManaged的任何长度键都有效?

C# 为什么RijndaelManaged的任何长度键都有效?,c#,.net,cryptography,rijndaelmanaged,C#,.net,Cryptography,Rijndaelmanaged,关于方法 RijndaelManaged.CreateDecryptor Method (Byte[], Byte[]) 它说的是关于第一个参数 用于对称算法的密钥。关键尺寸 必须是128、192或256位 但我可以将键设置为任意长度的字符串 var key = Encoding.UTF8.GetBytes("whetever..."); 为什么它对字节数组的长度不更挑剔呢?它如何确定要使用的三个键长度中的哪一个?任何键大小都不起作用。只允许使用一组特定的密钥大小 RijndaelManag

关于方法

RijndaelManaged.CreateDecryptor Method (Byte[], Byte[])
它说的是关于第一个参数

用于对称算法的密钥。关键尺寸 必须是128、192或256位

但我可以将键设置为任意长度的字符串

var key = Encoding.UTF8.GetBytes("whetever...");

为什么它对字节数组的长度不更挑剔呢?它如何确定要使用的三个键长度中的哪一个?

任何键大小都不起作用。只允许使用一组特定的密钥大小

RijndaelManaged
LegalKeySizes
sizes属性实际上报告了以下值:

MinSize = 128
MaxSize = 256
SkipSize = 64
这应该表明只支持AES密钥大小:128、192,当然还有256。这基本上意味着
RijndaelManaged
没有完全实现Rijndael,它还允许160和224位作为密钥大小。实际上,我认为它也不允许块大小为160和224位

现在,您的问题让我产生了一些疑问,因此我决定在不提出例外的情况下查看实际接受的关键尺寸,我得到了以下令人惊讶的结果:

8, 9, 10, 11, 12, 13, 14, 15, 16, 24, 32
或者,以位(而不是字节)表示:

64, 72, 80, 88, 96, 104, 112, 120, 128, 192, 256
因此,
RijndaelManaged
似乎接受比指定的密钥大小更多的密钥大小,并且这些额外的密钥大小低于类和Rijndael算法指定的最小长度

现在,让我们使用以下无效密钥大小加密某些内容:

064 : 1903b797b48ce006e618cb605d356981cc9b231195420010916e449037d3ac5b
072 : 1903b797b48ce006e618cb605d356981cc9b231195420010916e449037d3ac5b
080 : 1903b797b48ce006e618cb605d356981cc9b231195420010916e449037d3ac5b
088 : 1903b797b48ce006e618cb605d356981cc9b231195420010916e449037d3ac5b
096 : 4002ae70943dafdec10d4fbe2f97dc95b0a61e7412277197623b6d3d3e0da31c
104 : 4002ae70943dafdec10d4fbe2f97dc95b0a61e7412277197623b6d3d3e0da31c
112 : 4002ae70943dafdec10d4fbe2f97dc95b0a61e7412277197623b6d3d3e0da31c
120 : 4002ae70943dafdec10d4fbe2f97dc95b0a61e7412277197623b6d3d3e0da31c
128 : 66e94bd4ef8a2c3b884cfa59ca342b2e9434dec2d00fdac765f00c0c11628cd1
192 : aae06992acbf52a3e8f4a96ec9300bd71045be567103016ac50b21b86fc5457e
256 : dc95c078a2408989ad48a21492842087f3c003ddc4a7b8a94baedffc3d214c38
注意:对于那些感兴趣的人:密钥由所有零、明文和IV组成的CBC也只有16个字节设置为零。测试是在Windows 10上执行的:

操作系统:Microsoft Windows NT 10.0.10240.0,CLR:4.0.30319.42000

因此,对于密钥大小64、72、80、88、96、104、112、120,只会得到一些无效的、未指定的结果。查看代码,它基本上只使用8个字节作为键,对于键大小8..11,将其他字节设置为零,对于键大小12..15,将12个字节设置为键。在这种情况下,块大小将为128位,否则块大小将与密钥大小相同。因此,该实现实际上在用于密钥大小72、80、88、104、112和120位之前,从密钥末尾剥离一到三个字节

因此,基本上这似乎是实现中的一个bug。基本上,您不应该在
legalkeysize
返回的值之外使用
RijndaelManaged



如前所述,您应该使用将密码转换为具有有效密钥大小的密钥。

但最好提供密钥的完整长度和iv,不要依赖于填充。使用字符串作为密钥通常不是一个好主意,它会显著削弱您的保护。使用一个“密钥派生函数”,比如,你将密码+一个盐传递给它,它让你得到一个随机的
字节[]
输出,你可以输入密钥。它所做的事情是每次都会给你相同的
字节[]
密码和密码。但是密码不是字符串吗?A我应该把盐放在哪里?我不是已经在初始化向量(第二个参数)上实现了同样的目标吗?因为微软把参数验证搞砸了。相关:我几个月前就翻遍了那段代码。根据我的记忆,它将键填充到完整的32位单词,并根据单词数调整键的排列/轮次。你知道填充的类型吗?似乎前端只会生成一个大小的键,因此可能不需要调整轮次/键时间表..哦,天哪,它没有填充,它会去除字节。我不记得细节,但我记得被代码吓坏了。它甚至可能包含一些密钥大小的缓冲区溢出(由运行时检查数组索引捕获)。