使用AesCryptoServiceProvider获取不正确的解密值
我有以下代码使用AesCryptoServiceProvider
进行加密和解密。所使用的iv
和key
对于加密和解密都是相同的。解密值仍然与源字符串不同。使用AesCryptoServiceProvider获取不正确的解密值
- 什么需要纠正以获得解密后的原始值?
- 此代码适用于
inputValue = valid128BitString
。但是当inputString = “Test”
我得到以下例外Padding is invalid and cannot be removed.
。我们如何纠正它?
修订问题
下面将基于@jbtule答案做的伎俩。
从加密结果改变IV
值。假设加密是在一个单独的过程中完成的,我们如何知道解密的IV?有没有办法使其保持不变或已知?
答案:您的其他选项是通过IV加密并在开始加密转换之前分配它,而不是让aesProvider为您生成一个随机的加密转换。 - @Scott Chamberlain
aesProvider.IV = Convert.FromBase64String("4uy34C9sqOC9rbV4GD8jrA==");
更新:请参阅How to apply padding for Base64。我们可以使用UTF8
来编码源输入和结果输出。钥匙和IV可能保留在Base64
。
使用的Base64源输入会导致问题的一些的值,例如,“MyTest的”,其中的字符串的长度不是4
相关点的整数倍:
要解密的数据使用SymmetricAlgorithm类之一进行加密,必须将Key属性和IV属性设置为用于加密的相同值。
SymmetricAlgorithm.IV属性:来自前一个块的信息混合到加密下一个块的过程中。因此,两个相同的纯文本块的输出是不同的。由于该技术使用前一个块来加密下一个块,所以需要一个初始化向量来加密第一个数据块。(正如每SymmetricAlgorithm.IV Property MSDN文章)
有效键尺寸为:128,192,256位(根据How many characters to create a byte array for my AES method?)
主程序
class Program
{
static void Main(string[] args)
{
string valid128BitString = "AAECAwQFBgcICQoLDA0ODw==";
string inputValue = valid128BitString;
string keyValue = valid128BitString;
string iv = valid128BitString;
byte[] byteValForString = Convert.FromBase64String(inputValue);
EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue);
EncryptResult encyptedValue = new EncryptResult();
encyptedValue.IV = iv;
encyptedValue.EncryptedMsg = result.EncryptedMsg;
string finalResult = Convert.ToBase64String(Aes128Utility.DecryptData(encyptedValue, keyValue));
Console.WriteLine(finalResult);
if (String.Equals(inputValue, finalResult))
{
Console.WriteLine("Match");
}
else
{
Console.WriteLine("Differ");
}
Console.ReadLine();
}
}
AES实用
public static class Aes128Utility
{
private static byte[] key;
public static EncryptResult EncryptData(byte[] rawData, string strKey)
{
EncryptResult result = null;
if (key == null)
{
if (!String.IsNullOrEmpty(strKey))
{
key = Convert.FromBase64String((strKey));
result = Encrypt(rawData);
}
}
else
{
result = Encrypt(rawData);
}
return result;
}
public static byte[] DecryptData(EncryptResult encryptResult, string strKey)
{
byte[] origData = null;
if (key == null)
{
if (!String.IsNullOrEmpty(strKey))
{
key = Convert.FromBase64String(strKey);
origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV));
}
}
else
{
origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV));
}
return origData;
}
private static EncryptResult Encrypt(byte[] rawData)
{
using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
{
aesProvider.Key = key;
aesProvider.Mode = CipherMode.CBC;
aesProvider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream())
{
CryptoStream encStream = new CryptoStream(memStream, aesProvider.CreateEncryptor(), CryptoStreamMode.Write);
encStream.Write(rawData, 0, rawData.Length);
encStream.FlushFinalBlock();
EncryptResult encResult = new EncryptResult();
encResult.EncryptedMsg = Convert.ToBase64String(memStream.ToArray());
encResult.IV = Convert.ToBase64String(aesProvider.IV);
return encResult;
}
}
}
private static byte[] Decrypt(byte[] encryptedMsg, byte[] iv)
{
using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
{
aesProvider.Key = key;
aesProvider.IV = iv;
aesProvider.Mode = CipherMode.CBC;
aesProvider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream())
{
CryptoStream decStream = new CryptoStream(memStream, aesProvider.CreateDecryptor(), CryptoStreamMode.Write);
decStream.Write(encryptedMsg, 0, encryptedMsg.Length);
decStream.FlushFinalBlock();
return memStream.ToArray();
}
}
}
}
DTO类
public class EncryptResult
{
public string EncryptedMsg { get; set; }
public string IV { get; set; }
}
参考
很容易使密码原语执行的错误,人们做这一切的时候,最好使用high level library如果你能。
我有一个snippet,我试图保持审查和最新的,这非常接近你的工作。它还对密文进行验证,如果无论如何对手可以将选择的密文发送给解密实现,我会推荐进行验证,还有很多与修改密文有关的旁道攻击。
但是,如果你的密文不匹配你的密钥和iv,并且你没有验证你的iv和密文,你会遇到的问题与填充没有任何关系得到一个填充错误(如果这是冒泡客户端,它被称为padding oracle)。您需要将您的主要声明更改为:
string valid128BitString = "AAECAwQFBgcICQoLDA0ODw==";
string inputValue = "Test";
string keyValue = valid128BitString;
byte[] byteValForString = Encoding.UTF8.GetBytes(inputValue);
EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue);
EncryptResult encyptedValue = new EncryptResult();
encyptedValue.IV = result.IV; //<--Very Important
encyptedValue.EncryptedMsg = result.EncryptedMsg;
string finalResult =Encoding.UTF8.GetString(Aes128Utility.DecryptData(encyptedValue, keyValue));
因此,您使用相同的IV进行解密,就像您进行加密一样。
什么是实际的异常类型,你得到解密或加密?想知道因为'byte [] byteValForString = Convert.FromBase64String(“Test”);'对你的纯文本无效。 – jbtule 2013-02-18 15:32:19
你可以在Encrypt()和Decrypt()中使用'aesProvider.Padding = PaddingMode.None'吗?不知道为什么它使用相同的填充时出错? – Amitd 2013-02-18 15:51:47
@jbtule我在Decrypt()方法中遇到异常 - decStream.FlushFinalBlock();声明。填充无效,无法删除。 – Lijo 2013-02-18 16:00:59