填充是无效的,不能被删除?

我已经在网上查找这个例外与我的程序有什么关系,但似乎无法find解决办法或为什么发生在我的特定程序中。 我一直在使用提供我的MSDN的例子来encryption和解密使用Rijndaelalgorithm的XmlDocument。 encryption工作正常,但是当我尝试解密时,我得到以下exception:

填充无效,无法删除

谁能告诉我,我能做些什么来解决这个问题? 我的代码如下,我得到的关键和其他数据。 如果cryptoMode为false,它将调用解密方法,这是发生exception的地方:

public void Cryptography(XmlDocument doc, bool cryptographyMode) { RijndaelManaged key = null; try { // Create a new Rijndael key. key = new RijndaelManaged(); const string passwordBytes = "Password1234"; //password here byte[] saltBytes = Encoding.UTF8.GetBytes("SaltBytes"); Rfc2898DeriveBytes p = new Rfc2898DeriveBytes(passwordBytes, saltBytes); // sizes are devided by 8 because [ 1 byte = 8 bits ] key.IV = p.GetBytes(key.BlockSize/8); key.Key = p.GetBytes(key.KeySize/8); if (cryptographyMode) { Ecrypt(doc, "Content", key); } else { Decrypt(doc, key); } } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { // Clear the key. if (key != null) { key.Clear(); } } } private void Decrypt(XmlDocument doc, SymmetricAlgorithm alg) { // Check the arguments. if (doc == null) throw new ArgumentNullException("Doc"); if (alg == null) throw new ArgumentNullException("alg"); // Find the EncryptedData element in the XmlDocument. XmlElement encryptedElement = doc.GetElementsByTagName("EncryptedData")[0] as XmlElement; // If the EncryptedData element was not found, throw an exception. if (encryptedElement == null) { throw new XmlException("The EncryptedData element was not found."); } // Create an EncryptedData object and populate it. EncryptedData edElement = new EncryptedData(); edElement.LoadXml(encryptedElement); // Create a new EncryptedXml object. EncryptedXml exml = new EncryptedXml(); // Decrypt the element using the symmetric key. byte[] rgbOutput = exml.DecryptData(edElement, alg); <---- I GET THE EXCEPTION HERE // Replace the encryptedData element with the plaintext XML element. exml.ReplaceData(encryptedElement, rgbOutput); } 

Rijndael / AES是一个块密码。 它以128位(16个字符)的块encryption数据。 encryption填充用于确保消息的最后一个块总是正确的大小。

您的解密方法期待无论其默认填充是什么,并没有find它。 正如@ NetSquirrel所说,你需要明确地设置encryption和解密的填充。 除非你有其他理由,否则使用PKCS#7填充。

确保用于encryption解密的密钥相同 。 填充方法,即使没有明确设置,仍然应该允许正确的解密/encryption(如果没有设置,它们将是相同的)。 但是,如果你出于某种原因使用了一组不同的密钥来进行解密,那么你将会得到这个错误:

填充无效,无法删除

如果您使用某种algorithm来dynamic生成不起作用的密钥。 他们需要encryption和解密相同。 一个常见的方法是让调用者在encryption方法类的构造函数中提供密钥,以防止encryption/解密过程牵涉到创build这些项目。 它着重于手头的任务(encryption和解密数据),并要求主叫方提供ivkey

为了search人的利益,可能值得检查被解密的input。 在我的情况下,发送的解密信息(错误地)作为空string进入。 它导致了填充错误。

这可能与rossum的答案有关,但认为值得一提。

一个厮杀的时代,我终于解决了这个问题。
(注意:我使用标准的AES作为对称algorithm,这个答案可能不适合每个人。)

  1. 更改algorithm类。 将RijndaelManaged类replace为AESManaged类。
  2. 不要显式设置algorithm类的KeySize ,将它们保留为默认值。
    (这是非常重要的一步,我认为KeySize属性有一个bug。)

这里是你想检查你可能错过了哪个参数的列表:


  • (字节数组,对于不同的密钥大小,长度必须是16,24,32字节中的一个)。
  • IV
    (字节数组,16字节)
  • CipherMode
    (CBC,CFB,CTS,ECB,OFB之一)
  • PaddingMode
    (ANSIX923,ISO10126,无,PKCS7,零中的一个)

我的问题是,encryption的passPhrase不符合解密的passPhrase …所以它抛出了这个错误..有点误导。

如果使用相同的密钥和初始化vector进行编码和解码,则这个问题不是来自数据解码,而是来自数据编码。

在CryptoStream对象上调用Write方法之后,必须始终在Close方法之前调用FlushFinalBlock方法。

关于CryptoStream.FlushFinalBlock方法的MSDN文档说:
调用Close方法将调用FlushFinalBlock …
https://msdn.microsoft.com/en-US/library/system.security.cryptography.cryptostream.flushfinalblock(v=vs.110).aspx
这是错误的。 调用Close方法只是closuresCryptoStream和输出stream。
如果在写入要encryption的数据之后,在Close之前没有调用FlushFinalBlock,那么在解密数据时,CryptoStream对象上的Read或CopyTo方法调用将引发CryptographicExceptionexception(消息:“Padding无效且无法删除”)。

对于从SymmetricAlgorithm(Aes,DES,RC2,Rijndael,TripleDES)派生的所有encryptionalgorithm来说,这可能是正确的,尽pipe我刚刚validation了AesManaged和MemoryStream作为输出stream。

因此,如果您在解密时收到此CryptographicExceptionexception,请在写入要encryption的数据之后读取您的输出Stream Length属性值,然后调用FlushFinalBlock并再次读取其值。 如果它已经改变,你知道调用FlushFinalBlock不是可选的。

而且您不需要以编程方式执行任何填充,或者select另一个Padding属性值。 填充是FlushFinalBlock方法的作业。

………

凯文的其他评论:

是的,CryptoStream在调用Close之前调用FlushFinalBlock,但是为​​时已晚:当调用CryptoStream Close方法时,输出stream也被closures。

如果您的输出stream是MemoryStream,则在closures数据后无法读取其数据。 因此,在使用MemoryStream上写入的encryption数据之前,需要在CryptoStream上调用FlushFinalBlock。

如果你的输出stream是一个FileStream的话,情况会更糟,因为写入是被缓冲的。 如果在调用FileStream上的Flush之前closures输出stream,则最后写入的字节可能不会写入文件。 因此,在调用CryptoStream上的Close之前,首先需要在CryptoStream上调用FlushFinalBlock,然后在FileStream上调用Flush。

另一种情况,也是为了人们search的好处。

对我来说,这个错误发生在Dispose()方法中,它掩盖了与encryption无关的前一个错误。

一旦其他组件被修复,这个例外就消失了。

我遇到了这个填充错误,当我手动编辑文件中的encryption的string(使用记事本),因为我想testing如果我的encryption内容被手动更改将如何解密函数行为。

我的解决scheme是放置一个

  try decryption stuff.... catch inform decryption will not be carried out. end try 

就像我说我的填充错误是因为我手动input使用记事本解密的文本。 可能是我的答案可能会引导你到你的解决scheme。

固定我的解决scheme是我无意中应用不同的密钥encryption和解密方法。