【问题标题】:AES Padding is Invalid And Cannot Be RemovedAES 填充无效且无法删除
【发布时间】:2021-03-04 19:52:51
【问题描述】:

我在我的项目中使用 AES 密码算法来加密和解密我的值。我的代码几乎每次都能正常工作,但有时我会收到 Padding is invalid and cannot be removed 错误。我的项目是 ASP .NET Core 3.1 项目,它发布在 IIS Server 8.5 上。

正如Padding is invalid and cannot be removed? 9 年前提出的问题所说,我的密钥和盐总是设置为 128 位,填充模式总是设置为 PKCS#7,如下代码:aes.Padding = PaddingMode.PKCS7;

但有时,我会收到此错误。在使用 same 密钥、加盐和解密值调试我的代码后,我没有收到任何错误,而且我的代码还能正常工作 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;
    }
}

【问题讨论】:

  • 通过网络发送数据时使用 base64 或类似编码。二进制数据会产生问题。
  • 在关闭CryptoStream之前,您正在阅读MemoryStream;最后一个块可能没有被刷新。将您的 encrypted = ms.ToArray(); 移出使用。

标签: c# cryptography aes


【解决方案1】:

可能是因为您重用了相同的 ICryptoTransform 对象(_sifreleyici_desifreleyici)。在某些时候,转换对象不能再被重用,因此接口有一个属性来确定这一点。 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 抽象类的类。

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

【讨论】:

    猜你喜欢
    • 2016-07-18
    • 1970-01-01
    • 2020-12-26
    • 2016-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-17
    相关资源
    最近更新 更多