我正在尝试使用eith Rijndael或Aes以及下面的代码加密/解密字符串。
public class Crypto
{
private const string defaultVector = "asdfg123456789";
private const CipherMode cipherMode = CipherMode.CBC;
//Have tried PaddingMode.ISO10126, PaddingMode.None, and PaddingMode.PKCS7
private const PaddingMode paddingMode = PaddingMode.ISO10126;
private const int iterations = 2;
private static Rijndael GetCrypto(string passphrase)
{
var crypt = Rijndael.Create();
crypt.Mode = cipherMode;
crypt.Padding = paddingMode;
crypt.BlockSize = 256;
crypt.KeySize = 256;
crypt.Key =
new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
crypt.IV = new Rfc2898DeriveBytes(passphrase, Encoding.Unicode.GetBytes(defaultVector), iterations).GetBytes(32);
return crypt;
}
public static string Encrypt(string plainText, string passphrase)
{
byte[] clearData = Encoding.Unicode.GetBytes(plainText);
byte[] encryptedData;
var crypt = GetCrypto(passphrase);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearData, 0, clearData.Length);
//cs.FlushFinalBlock(); //Have tried this active and commented with no change.
}
encryptedData = ms.ToArray();
}
//Changed per Xint0's answer.
return Convert.ToBase64String(encryptedData);
}
public static string Decrypt(string cipherText, string passphrase)
{
//Changed per Xint0's answer.
byte[] encryptedData = Convert.FromBase64String(cipherText);
byte[] clearData;
var crypt = GetCrypto(passphrase);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encryptedData, 0, encryptedData.Length);
//I have tried adding a cs.FlushFinalBlock(); here as well.
}
clearData = ms.ToArray();
}
return Encoding.Unicode.GetString(clearData);
}
}
//编辑:我已根据下面的Xint0答案将Unicode调用更改为Convert.ToBase64String。
在Decrypt方法的cs.Write中,我收到“Padding无效且无法删除”的错误。
我已经尝试将填充设置为PaddingMode.None,但我得到“要加密的数据长度无效”。在加密方法中的cs.Write上。
我看过这些,他们所说的似乎没什么用。
Padding is invalid and cannot be removed
Padding is invalid and cannot be removed?
堆栈跟踪显示System.Security.CryptographicException来自RijndaelManagedTransform.DecryptData(Byte [] inputBuffer,Int32 inputOffset,Int32 inputCount,Byte []& outputBuffer,Int32 outputOffset,PaddingMode paddingMode,Boolean fLast)。
答案 0 :(得分:3)
我花了很多时间来查找导致 CryptographicException 的原因,我也在谷歌搜索包括Stackoverflow。 这是一个愚蠢的错误(通常在使用复制粘贴编程时),如下所示:
它从 CryptoStream 的实例抛出方法 FlushFinalBlock()。
查看错误代码:
CryptoStream cs = new CryptoStream(ms, rj.CreateDecryptor(rj.Key, rj.IV), CryptoStreamMode.Write);
我用它加密所以你可以看到 CryptoStreamMode。写 但是在同一条指令中我创建的是decryptor而不是加密器(参见构造函数中的第二个参数)。
小心并检查以避免浪费宝贵的时间;)
问候
布罗尼斯瓦夫
答案 1 :(得分:1)
我看到两个问题:
在调用ms.ToArray()
之前,您没有刷新和关闭流。将其更改为:
...
using (var cs = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearData, 0, clearData.Length);
cs.FlushFinalBlock();
cs.Close();
}
ms.Close();
encryptedData = ms.ToArray();
...
在Encrypt
中,生成的字节数组encryptedData
是 NOT 一个Unicode字符串,但您使用Unicode编码器从字节数组中获取字符串。而不是使用System.Convert.ToBase64String()
中的Encrypt
和System.Convert.FromBase64String()
中的Decrypt
。
在Encrypt
执行:
return System.Convert.ToBase64String(encryptedData);
在Decrypt
执行:
byte[] encryptedData = System.Convert.FromBase64String(cipherText);
修改强>
最大的问题是Encrypt
的返回值。加密Unicode字符串的字节表示的结果是 NOT Unicode字符串的字节表示。您不应将encryptedData
的值与Encoding.Unicode.GetString()
一起使用来获取加密数据的字符串表示形式。使用System.Convert.ToBase64String()
获取加密数据的字符串表示形式。请参阅Encoding Class MSDN文档中的备注部分。
编辑2
请注意,Rijndael不完全是AES,如果您与AES互操作,则块大小应始终为128位,与密钥大小无关。有关详细信息,请参阅here。
答案 2 :(得分:0)
我遇到了类似的问题,解密方法中的问题是初始化一个空的内存流。当我使用密文文本字节数组初始化它时它工作,如下所示:
MemoryStream ms = new MemoryStream(cipherText);