使用AES的解密数据的大小和字节错误
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用AES的解密数据的大小和字节错误相关的知识,希望对你有一定的参考价值。
在我们的项目中,我们使用follow方法在存储之前加密/解密重要数据。传入字节的大小始终为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更新,安全配置等)导致此类问题时,可能会出现这种情况吗?谢谢你的帮助。
UPD。添加了示例代码以证明具有错误密码的案例。加密字符串包含从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);
可以是任何其他情况(不正确的密码短语)来获取错误的解密数据?
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
,十六进制)。
以上是关于使用AES的解密数据的大小和字节错误的主要内容,如果未能解决你的问题,请参考以下文章