RijndaelManaged Decryption - 如何优雅地删除填充/0?

Posted

技术标签:

【中文标题】RijndaelManaged Decryption - 如何优雅地删除填充/0?【英文标题】:RijndaelManaged Decryption - How can I remove the padding /0 gracefully? 【发布时间】:2011-07-13 02:18:47 【问题描述】:

如何从解密的字符串中删除填充?我正在使用 RijndaelManaged 提供程序来加密和解密。当我解密时,字符串末尾有几个/0/0/0/0/0/0。我的问题是如何优雅地(正确地)从结果字符串中删除字符?

【问题讨论】:

你是如何解密数据的? Rijndael 是否填充明文? @Martinho Fernandes - Rijndael 以恒定大小(通常为 128、192 或 256 位)块加密数据。进出这些块大小需要更高级别的协议。 Rijndael 往返不会产生与输入不同的输出。 MSDN 有一个 sample 展示了如何使用 Rijndael 加密和解密数据,这些数据透明地使用您在 this answer 中设置的填充。 @Martinho Fernandes - 我指的是 NIST 指定的加密算法“Rijndael”。您指的是 .NET Framwork 类的“Rijndael”。在这种情况下,框架提供了我提到的“更高级别的协议”。 @Jeffrey:当然。但我也指的是算法。它要求输入是某个数字的倍数。你做填充。但是,无论您在加密时提供什么,在解密时都会得到什么,对吗? 【参考方案1】:

通过像这样使用TrimEnd()

theString.TrimEnd("/0");

【讨论】:

由于空字符在 .NET 字符串中是合法的,我个人认为这是一种不恰当的方法。 @Jeffrey:更糟糕的是,这不是空字符。这是一个斜线后跟一个零,有点“合法”。哦,它没有编译,因为 TrimEnd 需要一个字符数组。 我猜你的意思是theString.TrimEnd('\0');,它会从字符串末尾修剪空字符。除非解密后的字符串真的用斜线和零交替填充。【参考方案2】:

您可以在加密之前将字符串的长度添加到字符串的开头,然后在解密后使用长度来确定字符串的结束位置。

或者你可以在加密之前对字符串进行base64编码,然后再解码。

或在加密之前使用二进制或 XML 序列化程序对其进行编码。

所有这些方法的优点是它们允许您准确恢复存储的字符串。任何采用当前输出并猜测要应用什么转换的方法都没有该属性。

【讨论】:

你是对的,但更简单的是只选择正确的padding modes之一。【参考方案3】:

您很可能没有使用 RijndaelManaged 实例(在下面的代码中称为提供程序)的正确填充和块模式。由于 .NET 中的对称加密提供程序都是分组密码,因此这些设置会影响填充的工作方式(以及输出的安全性)。

以下设置将在使用 RijndaelManaged 时为您提供最佳安全性:

// set the padding algorithm
provider.Padding = PaddingMode.ISO10126; // default is PKCS7
// set the block chaining mode
provider.Mode = CipherMode.CBC;

如果您不是加密数据的人,并且您无法弄清楚发起方使用了哪些设置,那么您将在其他一些答案中找到帮助:)

【讨论】:

+1 我不知道这个信息,你有没有机会引用为什么这是最好的? CipherMode.CBC 本质上确保两个相同的输入块不会产生相同的加密输出,从而提高了安全性(参见en.wikipedia.org/wiki/Block_cipher_modes_of_operation)。 CBC 的缺点是需要 IV 并且需要按顺序执行。 PaddingMode 控制使用哪些字符来填充最后一块数据,直到使用的块大小。默认值为 (afaicr) 0s,它不如随机数据安全。检查 CipherMode 和 PaddingMode 的 MSDN 文档,因为我记得它们包含所有这些信息。【参考方案4】:

我看不出它与加密有什么关系。 IIUC 您已经完成了解密,并且有一个明文字符串,该字符串末尾有您想要删除的内容。如果是这样,您的问题是关于字符串操作,与您使用的加密算法无关。但也许我误解了..?

建议(可能不正确,但你会明白的):

string pattern = (i % 2 == 0? "/0" : "0/");
var sb = new StringBuilder(s);

int i = s.Length - 1;
while (sb[i] == pattern[i % 2]) --i;
sb.Length = i;
s = sb.ToString();

【讨论】:

问题可能不完全是关于 加密,但有问题的事件字符串似乎是 original string -> encryptiong process -> corrupted string ,所以它是关于修复加密过程。 块密码具有块大小,在 Rijndael 的情况下为 16 个字节。它仅适用于 16 字节的块。如果你有更少,那么你必须将数据填充为 16 个字节。这听起来很简单,而且确实很简单,只是当该块被解密时,结果是 16 个字节。现在有可能其中一些字节是“真实”数据,而一些是填充。解密者需要有某种方式知道。

以上是关于RijndaelManaged Decryption - 如何优雅地删除填充/0?的主要内容,如果未能解决你的问题,请参考以下文章

algorithm - C# 中的 RijndaelManaged 类是不是等同于 AES 加密?

使用 CryptDecrypt 解密 RijndaelManaged 加密字符串

让 .NET 中的 SlowAES 和 RijndaelManaged 类一起玩

RijndaelManaged 与 AesCryptoServiceProvider(AES 加密)

使用 RijndaelManaged 在 C# 中加密/解密流

RijndaelManaged 施工期间的奇怪行为