"Padding is invalid and cannot be removed" 异常
"Padding is invalid and cannot be removed" exception
我在这里看到很多人遇到这个异常的问题,但我根本不明白解决方案。
简短回顾:
我的程序是 C# 中的 GUI 程序,它假设在本地网络中的两台计算机上 运行 并且始终同步,因此,您会收到某种共享 space 以与另一台计算机上的朋友一起工作。
我的密码学在一个单例实例中,它负责我的程序的通信。以下是加密和解密数据的函数,它们接收数据作为文本或字节数组,return 将其作为字节数组或文本(取决于哪个,decrypt/encrypt):
public static byte[] Encrypt(string text)
{
desObj = Rijndael.Create();
byte[] cipherBytes;
byte[] plainBytes;
byte[] plainKey;
plainBytes = Encoding.ASCII.GetBytes(text);
plainKey= Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, desObj.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(plainBytes, 0, plainBytes.Length);
cs.Close();
cipherBytes = ms.ToArray();
ms.Close();
return cipherBytes;
}
public static string Decrypt(byte[] x)
{
byte[] plainBytes;
byte[] plainKey;
desObj = Rijndael.Create();
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read);
cs.Read(x, 0, x.Length);
plainBytes = ms.ToArray();
cs.Close();
ms.Close();
return Encoding.ASCII.GetString(plainBytes);
}
public static void RecievingMessage()
{
try
{
if (srvr != null && openForms != null)//openForms is a list of all the current open forms.
{
byte[] data = new byte[1024];
int i = 0;
string[] message;
if (srvr != null)
while (true)
{
Thread.Sleep(20);
int bytesRec = srvr.Receive(data);
message = Decrypt(data).Split(' ');
for (i = 0; i < openForms.Count; i++)
{
if (message[0].Equals(openForms[i].Name))
{
openForms[i].Recieve(message);
}
}
}
}
}
....//Catch clauses.
}
public static void SendMessage(string sender, string message)
{
if (srvr != null)
{
try
{
srvr.Send(Encrypt(sender + " " + message + " "));
}
...//Catch clauses.
}
}
当我运行这个程序时,控制台显示“Padding is invalid and cannot be removed”,我知道加密成功(我看到它在通过服务器时加密)但是当我尝试解密时,它会写入异常。
cs.Read(x, 0, x.Length)
并不是正确的做法。您需要将字节数组放入内存流的构造函数中,然后在循环中使用 cs.Read(
将数据读出到字符串中,直到读取所有字节。
public static string Decrypt(byte[] x)
{
StringBuilder plainString = new StringBuilder();
byte[] plainBytes = new byte[2048];
byte[] plainKey;
using(var desObj = Rijndael.Create()) //this should be a local variable and be disposed of.
{
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(MemoryStream ms = new MemoryStream(x)) //pass the byte[] in to the memory stream.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read)) //this should be disposed of instead of calling .Close manually.
{
int bytesRead;
while((bytesRead = cs.Read(plainBytes, 0, plainBytes.Lenght)) > 0)
{
var str = Encoding.ASCII.GetString(plainBytes, 0, bytesRead);
plainString.Append(str);
}
}
}
return str.ToString();
}
或将其包装在 StreamReader
中以使代码更简单。
public static string Decrypt(byte[] x)
{
byte[] plainKey;
using(var desObj = Rijndael.Create()) //this should be a local variable and be disposed of.
{
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(MemoryStream ms = new MemoryStream(x)) //pass the byte[] in to the memory stream.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read)) //this should be disposed of instead of calling .Close manually.
using(StreamReader sr = new StreamReader(cs, Encoding.ASCII))
{
return sr.ReadToEnd();
}
}
}
(注意:出于类似的原因,我建议将您的加密代码更改为 StreamWriter
。此外,ASCII 是一个糟糕的编码选择,它仅支持 7 位字符。改用 Enocding.UTF8
,它是一种更常见的编码,如果您不使用任何特殊字符,它仍将占用相同数量的 space,但如果您不丢失字符,像使用 ASCII 编码一样最终将它们包含在您的字符串中)
更新:您的代码存在第二个问题。您永远不会在发送方或接收方设置 desObj.IV
。如果您没有明确分配一个,它将使用随机生成的 IV。修复 MemoryStream 错误和 IV 错误将使代码正常工作。
这是一个完整的例子,你甚至可以 see run online
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
var key = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
var data = Encrypt("Hello World",key);
var str = Decrypt(data, key);
Console.WriteLine(str);
}
public static byte[] Encrypt(string plaintext, byte[] key)
{
using(var desObj = Rijndael.Create())
{
desObj.Key = key;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(var ms = new MemoryStream())
{
//Append the random IV that was generated to the front of the stream.
ms.Write(desObj.IV, 0, desObj.IV.Length);
//Write the bytes to be encrypted.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateEncryptor(), CryptoStreamMode.Write))
{
var plainTextBytes = Encoding.UTF8.GetBytes(plaintext);
cs.Write(plainTextBytes, 0, plainTextBytes.Length);
}
return ms.ToArray();
}
}
}
public static string Decrypt(byte[] cyphertext, byte[] key)
{
using(MemoryStream ms = new MemoryStream(cyphertext))
using(var desObj = Rijndael.Create())
{
desObj.Key = key;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
//Read the IV from the front of the stream and assign it to our object.
var iv = new byte[16];
var offset = 0;
while(offset < iv.Length)
{
offset += ms.Read(iv, offset, iv.Length - offset);
}
desObj.IV = iv;
//Read the bytes to be decrypted
using(var cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read))
using(var sr = new StreamReader(cs, Encoding.UTF8))
{
return sr.ReadToEnd();
}
}
}
}
我在这里看到很多人遇到这个异常的问题,但我根本不明白解决方案。 简短回顾: 我的程序是 C# 中的 GUI 程序,它假设在本地网络中的两台计算机上 运行 并且始终同步,因此,您会收到某种共享 space 以与另一台计算机上的朋友一起工作。 我的密码学在一个单例实例中,它负责我的程序的通信。以下是加密和解密数据的函数,它们接收数据作为文本或字节数组,return 将其作为字节数组或文本(取决于哪个,decrypt/encrypt):
public static byte[] Encrypt(string text)
{
desObj = Rijndael.Create();
byte[] cipherBytes;
byte[] plainBytes;
byte[] plainKey;
plainBytes = Encoding.ASCII.GetBytes(text);
plainKey= Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, desObj.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(plainBytes, 0, plainBytes.Length);
cs.Close();
cipherBytes = ms.ToArray();
ms.Close();
return cipherBytes;
}
public static string Decrypt(byte[] x)
{
byte[] plainBytes;
byte[] plainKey;
desObj = Rijndael.Create();
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read);
cs.Read(x, 0, x.Length);
plainBytes = ms.ToArray();
cs.Close();
ms.Close();
return Encoding.ASCII.GetString(plainBytes);
}
public static void RecievingMessage()
{
try
{
if (srvr != null && openForms != null)//openForms is a list of all the current open forms.
{
byte[] data = new byte[1024];
int i = 0;
string[] message;
if (srvr != null)
while (true)
{
Thread.Sleep(20);
int bytesRec = srvr.Receive(data);
message = Decrypt(data).Split(' ');
for (i = 0; i < openForms.Count; i++)
{
if (message[0].Equals(openForms[i].Name))
{
openForms[i].Recieve(message);
}
}
}
}
}
....//Catch clauses.
}
public static void SendMessage(string sender, string message)
{
if (srvr != null)
{
try
{
srvr.Send(Encrypt(sender + " " + message + " "));
}
...//Catch clauses.
}
}
当我运行这个程序时,控制台显示“Padding is invalid and cannot be removed”,我知道加密成功(我看到它在通过服务器时加密)但是当我尝试解密时,它会写入异常。
cs.Read(x, 0, x.Length)
并不是正确的做法。您需要将字节数组放入内存流的构造函数中,然后在循环中使用 cs.Read(
将数据读出到字符串中,直到读取所有字节。
public static string Decrypt(byte[] x)
{
StringBuilder plainString = new StringBuilder();
byte[] plainBytes = new byte[2048];
byte[] plainKey;
using(var desObj = Rijndael.Create()) //this should be a local variable and be disposed of.
{
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(MemoryStream ms = new MemoryStream(x)) //pass the byte[] in to the memory stream.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read)) //this should be disposed of instead of calling .Close manually.
{
int bytesRead;
while((bytesRead = cs.Read(plainBytes, 0, plainBytes.Lenght)) > 0)
{
var str = Encoding.ASCII.GetString(plainBytes, 0, bytesRead);
plainString.Append(str);
}
}
}
return str.ToString();
}
或将其包装在 StreamReader
中以使代码更简单。
public static string Decrypt(byte[] x)
{
byte[] plainKey;
using(var desObj = Rijndael.Create()) //this should be a local variable and be disposed of.
{
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(MemoryStream ms = new MemoryStream(x)) //pass the byte[] in to the memory stream.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read)) //this should be disposed of instead of calling .Close manually.
using(StreamReader sr = new StreamReader(cs, Encoding.ASCII))
{
return sr.ReadToEnd();
}
}
}
(注意:出于类似的原因,我建议将您的加密代码更改为 StreamWriter
。此外,ASCII 是一个糟糕的编码选择,它仅支持 7 位字符。改用 Enocding.UTF8
,它是一种更常见的编码,如果您不使用任何特殊字符,它仍将占用相同数量的 space,但如果您不丢失字符,像使用 ASCII 编码一样最终将它们包含在您的字符串中)
更新:您的代码存在第二个问题。您永远不会在发送方或接收方设置 desObj.IV
。如果您没有明确分配一个,它将使用随机生成的 IV。修复 MemoryStream 错误和 IV 错误将使代码正常工作。
这是一个完整的例子,你甚至可以 see run online
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
var key = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
var data = Encrypt("Hello World",key);
var str = Decrypt(data, key);
Console.WriteLine(str);
}
public static byte[] Encrypt(string plaintext, byte[] key)
{
using(var desObj = Rijndael.Create())
{
desObj.Key = key;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(var ms = new MemoryStream())
{
//Append the random IV that was generated to the front of the stream.
ms.Write(desObj.IV, 0, desObj.IV.Length);
//Write the bytes to be encrypted.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateEncryptor(), CryptoStreamMode.Write))
{
var plainTextBytes = Encoding.UTF8.GetBytes(plaintext);
cs.Write(plainTextBytes, 0, plainTextBytes.Length);
}
return ms.ToArray();
}
}
}
public static string Decrypt(byte[] cyphertext, byte[] key)
{
using(MemoryStream ms = new MemoryStream(cyphertext))
using(var desObj = Rijndael.Create())
{
desObj.Key = key;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
//Read the IV from the front of the stream and assign it to our object.
var iv = new byte[16];
var offset = 0;
while(offset < iv.Length)
{
offset += ms.Read(iv, offset, iv.Length - offset);
}
desObj.IV = iv;
//Read the bytes to be decrypted
using(var cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read))
using(var sr = new StreamReader(cs, Encoding.UTF8))
{
return sr.ReadToEnd();
}
}
}
}