【问题标题】:Wrong size and bytes of decrypted data using AES使用 AES 的解密数据的大小和字节错误
【发布时间】:2018-02-26 17:38:31
【问题描述】:

在我们的项目中,我们使用以下方法在存储之前对重要数据进行加密/解密。传入字节的大小始终为 32。请看一下:

public static string Encrypt(byte[] data, string pass)
{
    using (var algorithm = new RijndaelManaged())
    {
        algorithm.Padding = PaddingMode.PKCS7;

        var salt = new byte[32];
        new Random().NextBytes(salt);

        using (var rng = new Rfc2898DeriveBytes(pass, salt, 3072))
        {
            algorithm.Key = rng.GetBytes(algorithm.KeySize / 8);
            algorithm.IV = rng.GetBytes(algorithm.BlockSize / 8);

            using (var oms = new MemoryStream())
            {
                using (var ims = new MemoryStream(data))
                {
                    var encryptor = algorithm.CreateEncryptor();
                    var cs = new CryptoStream(oms, encryptor, CryptoStreamMode.Write);
                    ims.CopyTo(cs);
                    cs.FlushFinalBlock();
                }

                oms.Flush();

                var target = new byte[oms.Length + salt.Length];
                oms.ToArray().CopyTo(target, 0);
                salt.CopyTo(target, oms.Length);

                return Convert.ToBase64String(target);
            }
        }
    }
}

public static byte[] Decrypt(string data, string pass)
{
    var allbytes = Convert.FromBase64String(data);

    var salt = new byte[32];
    var databytes = new byte[allbytes.Length - salt.Length];

    Array.Copy(allbytes, databytes.Length, salt, 0, salt.Length);
    Array.Copy(allbytes, 0, databytes, 0, databytes.Length);

    using (var algorithm = new RijndaelManaged())
    {
        algorithm.Padding = PaddingMode.PKCS7;

        using (var rng = new Rfc2898DeriveBytes(pass, salt, 3072))
        {
            algorithm.Key = rng.GetBytes(algorithm.KeySize / 8);
            algorithm.IV = rng.GetBytes(algorithm.BlockSize / 8);

            using (var oms = new MemoryStream())
            {
                using (var ims = new MemoryStream(databytes))
                {
                    var decryptor = algorithm.CreateDecryptor();
                    using (var cs = new CryptoStream(ims, decryptor, CryptoStreamMode.Read))
                    {
                        cs.CopyTo(oms);
                    }
                }

                return oms.ToArray();
            }
        }
    }
}

这段代码在所有情况下都很好用。但是在客户环境中,我们在解密期间得到了 47 个字节而不是 32 个字节。经过一番调查,我意识到当使用不正确的密码短语时可能会发生这种行为(与加密不同,但在另一个字节组合中可以很好地解密)。但客户非常确定密码是正确的。可能是环境配置(Windows 或 .Net 更新、安全配置等)导致此类问题的情况? 感谢您的帮助。

更新。添加了示例代码以证明密码不正确。加密字符串包含从 1 到 32 的 32 个字节,并使用密码“p@ssW0rd”加密。如果使用正确的密码解密它,我们将得到 32 个字节,但如果使用“p4ssW7rd”,结果将包含 47 个字节。

        var password = "p@ssW0rd";
        var incorrectPassword = "p4ssW7rd";
        var encryptedData = "gP/MV6S09UYWc0pMgkkIqEdg204rToV/FQLpvktArWjAlIqjpbiPg5YX9zhPA9/gRuSbNtU5nyBKst54041uGeDNKSYJYvJc1UKZrMcqVFw=";

        var decryptedData = Decrypt(encryptedData, password);
        var incorrectDecryptedData = Decrypt(encryptedData, incorrectPassword);
        Console.WriteLine("Decrypted size: {0}, incorrect size: {1}", decryptedData.Length, incorrectDecryptedData.Length);

在任何其他情况下(密码不正确除外)都可能得到错误的解密数据?

【问题讨论】:

  • 如果解密不正确,你会得到错误。问题在于: var target = new byte[oms.Length + salt.Length];这意味着其中一个长度是错误的。
  • 没有解密代码是不可能知道发生了什么的。
  • @Gusman 有解密码,请更新页面
  • @jdweng 谢谢,但我确信长度是正确的。代码适用于许多其他情况
  • 代码按预期工作,您的客户一定是做错了什么。您的客户是否真的使用您发布的代码来解密数据?

标签: c# .net encryption cryptography aes


【解决方案1】:

AES-CBC 将愉快地解密为无效甚至随机数据。哪些数据取决于(错误的)密钥和密文。此外,PKCS#7 unpadding 不会执行任何完整的错误检测。创建它只是为了确保明文由 16 个字节块组成,因为 AES 一次只能加密 16 个字节(而 CBC 操作模式通常不会改变这一点)。

所以发生的情况是,对于某些密码,您可能会得到一个生成随机密文的密钥,这会意外地创建有效的 PKCS#7 填充。最可能的填充当然是具有值01 的单个字节,这表示只有一个字节的填充,可能性为 1/256。然后有两个字节填充 0202 但只有 1/65536 的可能性,等等。

要解决这种情况,您应该根据 IV 和密文计算 HMAC,或者使用经过身份验证的操作模式,例如 GCM。这将捕获 100% 的错误密钥/密文组合。


所以 47 字节的明文是 3 * 16 - 1,所以您偶然生成了一个 1 字节的填充 - 最简单的填充。由于总是发生填充,32 字节的明文确实应该扩展为 48 字节的密文,最多 16 字节的填充(全部为十六进制值10)。

【讨论】:

  • 谢谢,在我看来密码或密文不正确
猜你喜欢
  • 2020-02-12
  • 2015-12-24
  • 2015-02-20
  • 2015-01-11
  • 2011-03-18
  • 1970-01-01
  • 2021-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多