RijndaelManaged解密 - 我如何优雅地去除填充/0?

8

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


你是如何解密数据的?Rijndael是否填充明文? - R. Martinho Fernandes
1
@Martinho Fernandes - Rijndael加密数据以恒定大小的块(通常为128、192或256位)为单位。要达到和从这些块大小需要一个更高级别的协议。 - Jeffrey L Whitledge
使用Rijndael进行往返处理不会产生与输入不同的输出。 MSDN有一个示例,展示如何使用Rijndael加密和解密数据,该数据透明地使用您设置的填充,详见此答案 - R. Martinho Fernandes
@Martinho Fernandes - 我指的是由NIST指定的加密算法“Rijndael”。而你所指的是.NET Framework类中的“Rijndael”。在这种情况下,框架提供了我提到的“更高级别的协议”。 - Jeffrey L Whitledge
@Jeffrey:当然。但我也在提到算法。它需要输入是某个数字的倍数。你做填充。但无论你在加密时输入什么,解密时得到的就是什么? - R. Martinho Fernandes
@Martinho Fernandes - 是的,解密后的八位字节与加密的八位字节完全相同。但是某个地方必须将数据调整到正确的长度,以便Rijndael在其上施展魔法,而填充的长度将成为解密输出的内容。 - Jeffrey L Whitledge
4个回答

11

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

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

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

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


+1 我之前不知道这个信息,你能否提供一些证据来证明这是最佳选择? - Chris Marisic
2
CipherMode.CBC本质上确保两个相同的输入块不会产生相同的加密输出,从而提高了安全性(请参见http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation)。 CBC的缺点是需要IV并且执行需要顺序。 - Morten Mertner
2
PaddingMode 控制着用什么字符来填充最后一块数据,以达到块大小。默认值是(如果我没记错的话)0s,这比随机数据不够安全。请查看 MSDN 文档中的 CipherMode 和 PaddingMode,我记得它们包含了所有这些信息。 - Morten Mertner

5

使用TrimEnd()方法:

theString.TrimEnd("/0");

2
由于在.NET字符串中,空字符是合法的,因此我个人认为这是一种不恰当的方法。 - Jeffrey L Whitledge
1
@Jeffrey:更糟糕的是,这不是一个空字符。这是一个斜杠后面跟着一个零,有点“合法”。哦,而且它无法编译,因为TrimEnd需要一个字符数组。 - R. Martinho Fernandes
5
我猜你的意思是 theString.TrimEnd('\0');,它会将字符串末尾的空字符删除。除非解密后的字符串真的是用交替的反斜杠和零填充的。 - Greg

1

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

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

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

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


1
你是对的,但更简单的方法是只使用正确的 填充模式之一。 - President James K. Polk

0

我不明白这与加密有什么关系。如果我理解正确,您已经完成了解密,并且有一个明文字符串,在其末尾有一些您想要删除的内容。如果是这样,那么您的问题涉及字符串操作,而使用的加密算法无关紧要。但也许我误解了..?

建议(可能不正确,但您会得到思路):

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();

问题可能不是关于加密的,但是出现了一系列问题的字符串似乎是原始字符串-> 加密过程 -> 损坏的字符串,因此需要修复加密过程。 - Jeffrey L Whitledge
1
块密码有一个块大小,在Rijndael的情况下为16字节。它只能按16字节的块工作。如果你的数据少于16字节,你必须将其填充到恰好16字节。这听起来很容易,而且确实如此,但是当该块被解密时,结果是16字节。现在可能有一些字节是“真实”的数据,而另一些是填充。解密器需要知道某种方式。 - President James K. Polk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接