c# - 为什么密码错误会导致 "Padding is invalid and cannot be removed"?

标签 c# .net exception encryption

我需要一些简单的字符串加密,所以我编写了以下代码(从 here 获得了大量“灵感”):

    // create and initialize a crypto algorithm
    private static SymmetricAlgorithm getAlgorithm(string password) {
        SymmetricAlgorithm algorithm = Rijndael.Create();
        Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(
            password, new byte[] {
            0x53,0x6f,0x64,0x69,0x75,0x6d,0x20,             // salty goodness
            0x43,0x68,0x6c,0x6f,0x72,0x69,0x64,0x65
        }
        );
        algorithm.Padding = PaddingMode.ISO10126;
        algorithm.Key = rdb.GetBytes(32);
        algorithm.IV = rdb.GetBytes(16);
        return algorithm;
    }

    /* 
     * encryptString
     * provides simple encryption of a string, with a given password
     */
    public static string encryptString(string clearText, string password) {
        SymmetricAlgorithm algorithm = getAlgorithm(password);
        byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
        cs.Write(clearBytes, 0, clearBytes.Length);
        cs.Close();
        return Convert.ToBase64String(ms.ToArray());
    }

    /*
     * decryptString
     * provides simple decryption of a string, with a given password
     */
    public static string decryptString(string cipherText, string password) {
        SymmetricAlgorithm algorithm = getAlgorithm(password);
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write);
        cs.Write(cipherBytes, 0, cipherBytes.Length);
        cs.Close();            
        return System.Text.Encoding.Unicode.GetString(ms.ToArray());
    }

代码似乎工作正常,除了当使用不正确的 key 解密数据时,我在 decryptString 的 cs.Close() 行上收到 CryptographicException -“填充无效且无法删除”。

示例代码:

    string password1 = "password";
    string password2 = "letmein";
    string startClearText = "The quick brown fox jumps over the lazy dog";
    string cipherText = encryptString(startClearText, password1);
    string endClearText = decryptString(cipherText, password2);     // exception thrown

我的问题是,这是可以预料到的吗?我本以为用错误的密码解密只会导致无意义的输出,而不是异常。

最佳答案

虽然这已经得到解答,但我认为最好解释一下为什么这是可以预期的。

通常应用填充方案,因为大多数加密过滤器在语义上并不安全,并且可以防止某些形式的加密攻击。例如,通常在 RSA 中为 OAEP使用填充方案来防止某些类型的攻击(例如选择的明文攻击或 blinding )。

填充方案在发送消息之前将一些(通常)随机垃圾附加到消息 m 中。例如在OAEP方法中,使用了两个Oracle(这是简单的解释):

  1. 给定模数的大小,您用 0 填充 k1 位,用随机数填充 k0 位。
  2. 然后通过对消息应用一些转换,您可以获得经过加密和发送的填充消息。

这为您提供了消息的随机化以及一种测试消息是否为垃圾的方法。由于填充方案是可逆的,当您解密消息时,虽然您无法说明消息本身的完整性,但实际上您可以对填充做出一些断言,因此您可以知道消息是否已被正确解密或者你做错了什么(即有人篡改了消息或者你使用了错误的 key )

关于c# - 为什么密码错误会导致 "Padding is invalid and cannot be removed"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11762/

相关文章:

c# - 如何在 WPF 中将 UIElement 添加到 Grid

.net - 用于选择嵌套对象的 Linq 语法

java - Jboss 4.2 吞掉了 EJB 异常原因的堆栈跟踪,如何预防?

c# - 我应该如何处理此 C# 函数中的异常?

c# - ASP.NET Core 2.1 在 App Engine 中没有 HTTP/HTTPS 重定向

c# - DropdownListFor 所选值未在呈现的 html 中选择

c# - 如何在转换为PDF时保持word文档的字体属性

c# - WPF 数据虚拟化和 DataGrid

.net - 为什么perfmon无法看到我的自定义性能计数器的实例?

json - WCF WebFaultException 异常详细信息