RijndaelManaged“填充无效,无法删除”

时间:2019-06-04 03:23:20

标签: c# encryption

我正在尝试创建非常强大的Rijndael 256字符串加密方法,可以将其用于密码,但是在读取Padding is invalid and cannot be removed.并获取解密的字符串时,出现错误消息CryptoStream。这是我的加密和解密方法:

private string AES256EncryptString(string key, string plainText)
{
    try
    {
        using (RijndaelManaged rijndael = new RijndaelManaged())
        {
            rijndael.KeySize = 256;
            rijndael.BlockSize = 128;
            rijndael.Key = Encoding.UTF8.GetBytes(key);
            rijndael.GenerateIV();
            rijndael.Mode = CipherMode.CBC;
            rijndael.Padding = PaddingMode.PKCS7;
            ICryptoTransform encryptor = rijndael.CreateEncryptor(rijndael.Key, rijndael.IV);
            MemoryStream memoryStream = new MemoryStream();
            memoryStream.Write(rijndael.IV, 0, rijndael.IV.Length);
            CryptoStream crypoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            crypoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            crypoStream.FlushFinalBlock();
            crypoStream.Close();
            byte[] encryptedBytes = memoryStream.ToArray();
            memoryStream.Close();
            string encryptedText = Convert.ToBase64String(encryptedBytes);
            return encryptedText;
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
        return null;
    }
}

private string AES256DecryptString(string key, string encryptedText)
{
    try
    {
        using (RijndaelManaged rijndael = new RijndaelManaged())
        {
            rijndael.KeySize = 256;
            rijndael.BlockSize = 128;
            rijndael.Key = Encoding.UTF8.GetBytes(key);
            byte[] encryptedTextBytes = Encoding.UTF8.GetBytes(encryptedText);
            byte[] iv = new byte[16];
            Array.Copy(encryptedTextBytes, iv, iv.Length);
            rijndael.IV = iv;
            rijndael.Mode = CipherMode.CBC;
            rijndael.Padding = PaddingMode.PKCS7;
            ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);
            MemoryStream memoryStream = new MemoryStream();
            byte[] encryptedTextWithoutIVBytes = new byte[encryptedTextBytes.Length - iv.Length];
            Array.Copy(encryptedTextBytes, 16, encryptedTextWithoutIVBytes, 0, encryptedTextWithoutIVBytes.Length);
            memoryStream.Write(encryptedTextWithoutIVBytes, 0, encryptedTextWithoutIVBytes.Length);
            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            StreamReader streamReader = new StreamReader(cryptoStream);
            string decryptedText = streamReader.ReadToEnd();
            cryptoStream.FlushFinalBlock();
            cryptoStream.Close();
            memoryStream.Close();
            return decryptedText;
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
        return null;
    }
}

您可以看到,在添加加密位之前,我在加密字符串之前添加了初始化向量,因为我知道IV应该是随机的,并且我已经看到这是一个很好的使用策略。我确保在解密之前先删除IV。

有没有一种方法可以解决此问题而无需更改填充模式(我已经知道PKCS7填充非常安全)?

1 个答案:

答案 0 :(得分:1)

问题:

  1. 对于密码和类似的低熵密钥,应使用适当的基于密码的KDF。 .NET具有Rfc2898DeriveBytes(PBKDF2)类,使此操作相对容易。

  2. 您不是在解密器中使用base64解码密文。代替

    byte[] encryptedTextBytes = Encoding.UTF8.GetBytes(encryptedText);
    

    您应该拥有

    byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText);
    
  3. 用密文字节填充MemoryStream之后,需要重置MemoryStream的位置。之后

    memoryStream.Write(encryptedTextWithoutIVBytes, 0, encryptedTextWithoutIVBytes.Length);
    

    您需要插入

    memoryStream.Seek(0, SeekOrigin.Begin);