简体   繁体   English

AES 填充无效且无法移除

[英]AES Padding is Invalid And Cannot Be Removed

I am using AES criptography algorithms to encrypt and decrypt my values in my project.我正在使用 AES 密码算法来加密和解密我的项目中的值。 My code works almost everytime but sometimes I get Padding is invalid and cannot be removed error.我的代码几乎每次都有效,但有时我得到Padding is invalid and cannot be removed错误。 My project is ASP .NET Core 3.1 project and it's published on IIS Server 8.5.我的项目是 ASP .NET Core 3.1 项目,它发布在 IIS Server 8.5 上。

As said at Padding is invalid and cannot be removed?正如在Padding 是无效的,不能被删除? question asked 9 years ago, my keys and salts are always set 128 bits and padding mode is always set to PKCS#7 like this code: aes.Padding = PaddingMode.PKCS7; 9 年前提出的问题,我的密钥和盐总是设置为 128 位,填充模式总是设置为 PKCS#7,如下代码: aes.Padding = PaddingMode.PKCS7; . .

But sometimes, I got this error.但有时,我得到了这个错误。 After debugging my code with the same key, salt and decrypted value I didn't get any error and my code works fine for another 10 hours or so.在使用相同的密钥、盐和解密值调试我的代码后,我没有收到任何错误,并且我的代码可以正常工作 10 个小时左右。 I have no idea why my code behaves like this but I couldn't find any solution.我不知道为什么我的代码会这样,但我找不到任何解决方案。

My Constructor:我的构造函数:

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);
}

My encrption code:我的加密代码:

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;
    }
}

My decryption code:我的解密代码:

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;
    }
}

Probably because you are reusing the same ICryptoTransform objects ( _sifreleyici and _desifreleyici ).可能是因为您正在重用相同的ICryptoTransform对象( _sifreleyici_desifreleyici )。 At some point, the transform object can't be reused anymore and therefore the interface has a property to determine that.在某些时候,变换 object 不能再被重用,因此接口具有确定这一点的属性。 The ICryptoTransform.CanReuseTransform property. ICryptoTransform.CanReuseTransform属性。

Consequently, you need to check this property and recreate the objects when you get false .因此,您需要检查此属性并在获得false时重新创建对象。

Example例子

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;
    }
}

Then use these two properties in the related methods to create the CryptoStream .然后在相关方法中使用这两个属性来创建CryptoStream


Alternative选择

I'd like to propose the code below as an alternative that can be used with the classes that derive from the SymmetricAlgorithm abstract class.我想提出下面的代码作为替代方案,它可以与派生自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();
}

Usage:用法:

void SomeCaller()
{
    using (var crypt = new SymmetricCrypto<AesManaged>("password"))
    {
        var bytes = crypt.Encrypt("Plain Text....");
        // ...

        var plainText = crypt.Decrypt(bytes);
        // ...
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM