我见过许多人在这里遇到这个例外的问题,但我根本不理解解决方案。 简短回顾: 我的程序是C#中的一个GUI程序,它假设在本地网络中的两台计算机上运行并且始终同步,因此,您会收到某种共享空间,以便与另一台计算机上的朋友一起工作。 我的加密是在一个单例实例中,它负责我的程序的通信。以下是加密和解密数据的函数,它们将这些数据作为文本或字节数组接收,并将其作为字节数组或文本返回(取决于哪一个,解密/加密):
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.
}
}
当我运行此程序时,控制台上显示“填充无效且无法删除”,我知道加密成功(我看到它在通过服务器时加密)但是当我尝试解密时写下例外。
答案 0 :(得分:1)
执行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位字符。使用{{ 1}}相反,它是一个更常见的编码,如果你不使用任何特殊字符仍然会占用相同数量的空间,但如果你最终在你的字符串中使用它们就不会丢失字符你将使用ASCII编码)
更新:您的代码存在第二个问题。您从未在发送方或接收方设置Enocding.UTF8
。如果您没有明确指定IV,它将使用随机生成的IV。修复MemoryStream错误和IV错误将使代码工作。
以下是一个完整的示例,您甚至可以see run online
desObj.IV