我有一个C#WinForms应用程序,带有AES加密/解密功能。加密(解密)本身工作正常,但只有一次。如果我尝试加密另一个字符串,我会收到一个CryptographyException,说填充是无效的。基于一些研究,似乎我忘了关闭一些流,但我无法弄清楚它是什么。有谁知道如何解决这一问题? 这是我使用的代码(我相信我之前发现它的某些内容):
static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key
, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key
, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt
, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(
csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
//csDecrypt.FlushFinalBlock(); causes an exception
plaintext = srDecrypt.ReadToEnd();
//csDecrypt.Flush(); experimental solution, doesn't work either
srDecrypt.Close();
}
csDecrypt.Close();
}
msDecrypt.Close();
}
}
return plaintext;
}
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key,
byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key
, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt
, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(
csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
swEncrypt.Close();
}
csEncrypt.Close();
msEncrypt.Close();
encrypted = msEncrypt.ToArray();
//csEncrypt.FlushFinalBlock(); causes an exception saying it was already called
}
}
}
以下是我用来测试ecnryption的代码示例。正确执行,但只执行一次...... 密钥和IV被转换为Unicode字符串,以便用户能够保存它并在以后用于解密。
private void button7_Click(object sender, EventArgs e)
{
string aesKey = "";
string aesIV = "";
string ciphered = "";
string deciphered = "";
using (Aes myAes = Aes.Create())
{
myAes.GenerateKey();
myAes.GenerateIV();
aesKey = Encoding.Unicode.GetString(myAes.Key);
aesIV = Encoding.Unicode.GetString(myAes.IV);
ciphered = Encoding.Unicode.GetString(EncryptStringToBytes_Aes(".ahoj.", myAes.Key, myAes.IV));
byte[] deKey = Encoding.Unicode.GetBytes(aesKey);
byte[] deIv = Encoding.Unicode.GetBytes(aesIV);
deciphered = DecryptStringFromBytes_Aes(Encoding.Unicode.GetBytes(ciphered), deKey, deIv);
MessageBox.Show("key: " + aesKey + "\niv: " + aesIV + "\ndekey: " + Encoding.Unicode.GetString(deKey) + "\ndeIv: " + Encoding.Unicode.GetString(deIv) + "\nDeciphered: " + deciphered);
}
}
答案 0 :(得分:0)
我建议使用base 64编码字节,而不是使用unicode编码中的GetBytes
和GetString
。
您可以使用Convert.ToBase64String()
和Convert.FromBase64String
进行base 64编码。
从生成的字节数组中获取unicode字符串的一个问题是无法保证所有字符都是可打印字符。例如,如果字节数组中有0,那么它将是一个空控制字符。
答案 1 :(得分:0)
我最近遇到了这个问题。我正在使用&#39;使用&#39;您的第一个代码块中的语句,但我从不致电.Close()
,我没有遇到只能运行一次的问题。
要解决在解密和发布不可打印字符时填充的问题,我明确设置Padding
,就像您在第一个代码块中所做的那样,但我使用Encoding.Default.GetBytes(cipherText);
和{{1相同编码的方法,因此它使用Window的默认扩展ASCII编码,因此它将识别所有字符。