我已经看过其他一些有关此问题的帖子,但我不确定如何将它们应用到我的场景中。奇怪的是,我昨晚成功地运行了这个,当我今天回到它时,它正在抛出CryptographicException
Specified padding mode is not valid for this algorithm.
其他帖子引用了IV的处理方式,但似乎包含在AesManaged
类中。
我需要在此处调整以解决此问题?
public class SymetricEncryptionHelper
{
private static int Rfc2898KeygenIterations = 100;
private static int AesKeySizeInBits = 128;
/// <summary>
/// Creates an encrypted version of the plain text string and it's salt
/// </summary>
/// <param name="plainTextString"></param>
/// <param name="encryptionPassword"></param>
/// <returns>Tuple of String, String (encrypted string, salt)</returns>
public static Tuple<string, string> Encrypt(string plainTextString, string encryptionPassword)
{
byte[] Salt = new byte[16];
var rnd = new Random();
rnd.NextBytes(Salt);
byte[] rawPlaintext = Encoding.Unicode.GetBytes(plainTextString);
byte[] cipherText = null;
using (Aes aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = AesKeySizeInBits;
int KeyStrengthInBytes = aes.KeySize / 8;
var rfc2898 = new Rfc2898DeriveBytes(encryptionPassword, Salt, Rfc2898KeygenIterations);
aes.Key = rfc2898.GetBytes(KeyStrengthInBytes);
aes.IV = rfc2898.GetBytes(KeyStrengthInBytes);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(rawPlaintext, 0, rawPlaintext.Length);
}
cipherText = ms.ToArray();
}
}
return new Tuple<string, string>(Encoding.Unicode.GetString(cipherText), Encoding.Unicode.GetString(Salt));
}
/// <summary>
/// Returns the decrypted string
/// </summary>
/// <param name="cipherTextString"></param>
/// <param name="cipherSalt"></param>
/// <param name="encryptionPassword"></param>
/// <returns>String</returns>
public static string Decrypt(string cipherTextString, string cipherSalt, string encryptionPassword)
{
byte[] Salt = Encoding.Unicode.GetBytes(cipherSalt);
byte[] cipherText = Encoding.Unicode.GetBytes(cipherTextString);
byte[] plainText = null;
using (Aes aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = AesKeySizeInBits;
int KeyStrengthInBytes = aes.KeySize / 8;
var rfc2898 = new Rfc2898DeriveBytes(encryptionPassword, Salt, Rfc2898KeygenIterations);
aes.Key = rfc2898.GetBytes(KeyStrengthInBytes);
aes.IV = rfc2898.GetBytes(KeyStrengthInBytes);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherText, 0, cipherText.Length);
}
plainText = ms.ToArray();
}
}
return Encoding.Unicode.GetString(plainText);
}
}
答案 0 :(得分:2)
您无法使用Encoding.Unicode.GetString
将随机字节转换为字符,因为并非所有组合都是有效的UTF-16代码点序列。遇到非法序列时,解码器将回退给您U+FFFD REPLACEMENT CHARACTER
,修改原始字节并确保解密失败。这是一段简单的代码来说明问题:
byte[] b = new byte[4];
var r = new Random();
while (true) {
r.NextBytes(b);
var s = Encoding.Unicode.GetString(b);
var expected = b;
var actual = Encoding.Unicode.GetBytes(s);
if (!actual.SequenceEqual(expected)) {
Console.WriteLine(
$"Fail: expected {BitConverter.ToString(expected)}, " +
$"got {BitConverter.ToString(actual)}"
);
break;
}
}
这应该很快就会出现
失败:预期3B-DC-5C-52,得到FD-FF-5C-52
一个简单的解决方法是使用Convert.ToBase64String
和Convert.FromBase64String
代替,因为这会进行往返。