AES 填充无效且无法删除
AES Padding is Invalid And Cannot Be Removed
我在我的项目中使用 AES 加密算法来加密和解密我的值。我的代码几乎每次都能正常工作,但有时我会收到 Padding is invalid and cannot be removed
错误。我的项目是 ASP .NET Core 3.1 项目,它发布在 IIS Server 8.5 上。
正如 9 年前在 Padding is invalid and cannot be removed? 问题中所说,我的密钥和盐始终设置为 128 位,填充模式始终设置为 PKCS#7,如下代码所示:aes.Padding = PaddingMode.PKCS7;
.
但有时,我会遇到此错误。在使用 same 密钥、salt 和解密值调试我的代码后,我没有收到任何错误,我的代码还能正常工作 10 个小时左右。我不知道为什么我的代码会这样,但我找不到任何解决方案。
我的构造函数:
public void KriptoAlgoritmasiniAyarla(string password, string salt, SymmetricAlgorithm algorithm)
{
if (password == null) throw new ArgumentNullException(nameof(password));
if (salt == null) throw new ArgumentNullException(nameof(salt));
DeriveBytes rgb = new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(salt));
var rgbKey = rgb.GetBytes(algorithm.KeySize >> 3);
var rgbIv = rgb.GetBytes(algorithm.BlockSize >> 3);
_sifreleyici = algorithm.CreateEncryptor(rgbKey, rgbIv);
_desifreleyici = algorithm.CreateDecryptor(rgbKey, rgbIv);
}
我的加密代码:
public byte[] ByteDizisineSifrele(string plainText)
{
try
{
byte[] encrypted;
// Create a new AesManaged.
using (AesManaged aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
// Create MemoryStream
using (MemoryStream ms = new MemoryStream())
{
// Create crypto stream using the CryptoStream class. This class is the key to encryption
// and encrypts and decrypts data from any given stream. In this case, we will pass a memory stream
// to encrypt
using (CryptoStream cs = new CryptoStream(ms, _sifreleyici, CryptoStreamMode.Write))
{
// Create StreamWriter and write data to a stream
using (StreamWriter sw = new StreamWriter(cs))
sw.Write(plainText);
encrypted = ms.ToArray();
}
}
}
// Return encrypted data
return encrypted;
}
catch (Exception exp)
{
throw exp;
}
}
我的解密码:
public string ByteDizisiDesifreEt(byte[] cipherText)
{
try
{
string plaintext = null;
// Create AesManaged
using (AesManaged aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
// Create the streams used for decryption.
using (MemoryStream ms = new MemoryStream(cipherText))
{
// Create crypto stream
using (CryptoStream cs = new CryptoStream(ms, _desifreleyici, CryptoStreamMode.Read))
{
// Read crypto stream
using (StreamReader reader = new StreamReader(cs))
plaintext = reader.ReadToEnd();
}
}
}
return plaintext;
}
catch (Exception exp)
{
throw exp;
}
}
可能是因为您重复使用了相同的 ICryptoTransform
objects (_sifreleyici
and _desifreleyici
). At some point, the transform object can't be reused anymore and therefore the interface has a property to determine that. The ICryptoTransform.CanReuseTransform
属性.
因此,您需要检查此 属性 并在获得 false
时重新创建对象。
例子
private readonly byte[] Key, IV;
public void KriptoAlgoritmasiniAyarla(
string password,
string salt,
SymmetricAlgorithm algorithm)
{
// ...
Key = // Get the key..
IV = // Get the IV..
}
private ICryptoTransform encryptor;
private ICryptoTransform Encryptor
{
get
{
if (encryptor == null || !encryptor.CanReuseTransform)
{
encryptor?.Dispose();
encryptor = Algorithm.CreateEncryptor(Key, IV);
}
return encryptor;
}
}
private ICryptoTransform decryptor;
private ICryptoTransform Decryptor
{
get
{
if (decryptor == null || !decryptor.CanReuseTransform)
{
decryptor?.Dispose();
decryptor = Algorithm.CreateDecryptor(Key, IV);
}
return decryptor;
}
}
然后在相关方法中使用这两个属性创建CryptoStream
.
备选
我想推荐下面的代码作为替代方案,它可以与从 SymmetricAlgorithm
摘要 class.
派生的 classes 一起使用
public class SymmetricCrypto<T> : IDisposable where T : SymmetricAlgorithm, new()
{
private readonly T Algorithm = new T();
public SymmetricCrypto()
{
Algorithm.GenerateKey();
Algorithm.GenerateIV();
}
public SymmetricCrypto(byte[] key, byte[] iv)
{
Algorithm.Key = key;
Algorithm.IV = iv;
}
public SymmetricCrypto(string pass)
{
var bytes = Encoding.UTF8.GetBytes(pass);
var rfc = new Rfc2898DeriveBytes(pass,
new SHA256Managed().ComputeHash(bytes), 1000);
Algorithm.Key = rfc.GetBytes(Algorithm.LegalKeySizes[0].MaxSize / 8);
Algorithm.IV = rfc.GetBytes(Algorithm.LegalBlockSizes[0].MinSize / 8);
}
public SymmetricCrypto(byte[] pass)
{
var rfc = new Rfc2898DeriveBytes(pass,
new SHA256Managed().ComputeHash(pass), 1000);
Algorithm.Key = rfc.GetBytes(Algorithm.LegalKeySizes[0].MaxSize / 8);
Algorithm.IV = rfc.GetBytes(Algorithm.LegalBlockSizes[0].MinSize / 8);
}
public byte[] Encrypt(string input) =>
Transform(Encoding.UTF8.GetBytes(input), Algorithm.CreateEncryptor());
public string Decrypt(byte[] input) =>
Encoding.UTF8.GetString(Transform(input, Algorithm.CreateDecryptor()));
private byte[] Transform(byte[] input, ICryptoTransform cryptoTrans)
{
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, cryptoTrans, CryptoStreamMode.Write))
{
cs.Write(input, 0, input.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}
public void Dispose() => Algorithm.Dispose();
}
用法:
void SomeCaller()
{
using (var crypt = new SymmetricCrypto<AesManaged>("password"))
{
var bytes = crypt.Encrypt("Plain Text....");
// ...
var plainText = crypt.Decrypt(bytes);
// ...
}
}
我在我的项目中使用 AES 加密算法来加密和解密我的值。我的代码几乎每次都能正常工作,但有时我会收到 Padding is invalid and cannot be removed
错误。我的项目是 ASP .NET Core 3.1 项目,它发布在 IIS Server 8.5 上。
正如 9 年前在 Padding is invalid and cannot be removed? 问题中所说,我的密钥和盐始终设置为 128 位,填充模式始终设置为 PKCS#7,如下代码所示:aes.Padding = PaddingMode.PKCS7;
.
但有时,我会遇到此错误。在使用 same 密钥、salt 和解密值调试我的代码后,我没有收到任何错误,我的代码还能正常工作 10 个小时左右。我不知道为什么我的代码会这样,但我找不到任何解决方案。
我的构造函数:
public void KriptoAlgoritmasiniAyarla(string password, string salt, SymmetricAlgorithm algorithm)
{
if (password == null) throw new ArgumentNullException(nameof(password));
if (salt == null) throw new ArgumentNullException(nameof(salt));
DeriveBytes rgb = new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(salt));
var rgbKey = rgb.GetBytes(algorithm.KeySize >> 3);
var rgbIv = rgb.GetBytes(algorithm.BlockSize >> 3);
_sifreleyici = algorithm.CreateEncryptor(rgbKey, rgbIv);
_desifreleyici = algorithm.CreateDecryptor(rgbKey, rgbIv);
}
我的加密代码:
public byte[] ByteDizisineSifrele(string plainText)
{
try
{
byte[] encrypted;
// Create a new AesManaged.
using (AesManaged aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
// Create MemoryStream
using (MemoryStream ms = new MemoryStream())
{
// Create crypto stream using the CryptoStream class. This class is the key to encryption
// and encrypts and decrypts data from any given stream. In this case, we will pass a memory stream
// to encrypt
using (CryptoStream cs = new CryptoStream(ms, _sifreleyici, CryptoStreamMode.Write))
{
// Create StreamWriter and write data to a stream
using (StreamWriter sw = new StreamWriter(cs))
sw.Write(plainText);
encrypted = ms.ToArray();
}
}
}
// Return encrypted data
return encrypted;
}
catch (Exception exp)
{
throw exp;
}
}
我的解密码:
public string ByteDizisiDesifreEt(byte[] cipherText)
{
try
{
string plaintext = null;
// Create AesManaged
using (AesManaged aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
// Create the streams used for decryption.
using (MemoryStream ms = new MemoryStream(cipherText))
{
// Create crypto stream
using (CryptoStream cs = new CryptoStream(ms, _desifreleyici, CryptoStreamMode.Read))
{
// Read crypto stream
using (StreamReader reader = new StreamReader(cs))
plaintext = reader.ReadToEnd();
}
}
}
return plaintext;
}
catch (Exception exp)
{
throw exp;
}
}
可能是因为您重复使用了相同的 ICryptoTransform
objects (_sifreleyici
and _desifreleyici
). At some point, the transform object can't be reused anymore and therefore the interface has a property to determine that. The ICryptoTransform.CanReuseTransform
属性.
因此,您需要检查此 属性 并在获得 false
时重新创建对象。
例子
private readonly byte[] Key, IV;
public void KriptoAlgoritmasiniAyarla(
string password,
string salt,
SymmetricAlgorithm algorithm)
{
// ...
Key = // Get the key..
IV = // Get the IV..
}
private ICryptoTransform encryptor;
private ICryptoTransform Encryptor
{
get
{
if (encryptor == null || !encryptor.CanReuseTransform)
{
encryptor?.Dispose();
encryptor = Algorithm.CreateEncryptor(Key, IV);
}
return encryptor;
}
}
private ICryptoTransform decryptor;
private ICryptoTransform Decryptor
{
get
{
if (decryptor == null || !decryptor.CanReuseTransform)
{
decryptor?.Dispose();
decryptor = Algorithm.CreateDecryptor(Key, IV);
}
return decryptor;
}
}
然后在相关方法中使用这两个属性创建CryptoStream
.
备选
我想推荐下面的代码作为替代方案,它可以与从 SymmetricAlgorithm
摘要 class.
public class SymmetricCrypto<T> : IDisposable where T : SymmetricAlgorithm, new()
{
private readonly T Algorithm = new T();
public SymmetricCrypto()
{
Algorithm.GenerateKey();
Algorithm.GenerateIV();
}
public SymmetricCrypto(byte[] key, byte[] iv)
{
Algorithm.Key = key;
Algorithm.IV = iv;
}
public SymmetricCrypto(string pass)
{
var bytes = Encoding.UTF8.GetBytes(pass);
var rfc = new Rfc2898DeriveBytes(pass,
new SHA256Managed().ComputeHash(bytes), 1000);
Algorithm.Key = rfc.GetBytes(Algorithm.LegalKeySizes[0].MaxSize / 8);
Algorithm.IV = rfc.GetBytes(Algorithm.LegalBlockSizes[0].MinSize / 8);
}
public SymmetricCrypto(byte[] pass)
{
var rfc = new Rfc2898DeriveBytes(pass,
new SHA256Managed().ComputeHash(pass), 1000);
Algorithm.Key = rfc.GetBytes(Algorithm.LegalKeySizes[0].MaxSize / 8);
Algorithm.IV = rfc.GetBytes(Algorithm.LegalBlockSizes[0].MinSize / 8);
}
public byte[] Encrypt(string input) =>
Transform(Encoding.UTF8.GetBytes(input), Algorithm.CreateEncryptor());
public string Decrypt(byte[] input) =>
Encoding.UTF8.GetString(Transform(input, Algorithm.CreateDecryptor()));
private byte[] Transform(byte[] input, ICryptoTransform cryptoTrans)
{
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, cryptoTrans, CryptoStreamMode.Write))
{
cs.Write(input, 0, input.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}
public void Dispose() => Algorithm.Dispose();
}
用法:
void SomeCaller()
{
using (var crypt = new SymmetricCrypto<AesManaged>("password"))
{
var bytes = crypt.Encrypt("Plain Text....");
// ...
var plainText = crypt.Decrypt(bytes);
// ...
}
}