使用AesCryptoServiceProvider获取不正确的解密值

我有以下代码使用AesCryptoServiceProvider进行加密和解密。 加密和解密使用的ivkey相同。 解密值仍然与源字符串不同。

  1. 解密后需要更正才能获得原始值?
  2. inputValue = valid128BitString时,此代码正在运行。 但是当inputString = “Test”我得到以下exception, Padding is invalid and cannot be removed. 。 我们怎样才能纠正它?

更新的问题

以下将根据@jbtule答案进行操作。

 encyptedValue.IV = result.IV; 

加密结果的IV值发生变化。 假设加密是在一个单独的过程中完成的,我们怎么知道IV用于解密? 有没有办法让它保持不变或已知?

答:您的另一个选择是通过IV进入加密并在开始加密转换之前分配它,而不是让aesProvider为您生成随机的。 – @Scott Chamberlain

  aesProvider.IV = Convert.FromBase64String("4uy34C9sqOC9rbV4GD8jrA=="); 

更新:请参阅如何为Base64应用填充 。 我们可以使用UTF8来编码源输入和结果输出。 密钥和IV可以保留在Base64

使用Base64进行源输入会导致某些值出现问题,例如“MyTest”,其中字符串的长度不是4的倍数

相关要点:

要解密使用其中一个SymmetricAlgorithm类加密的数据,必须将Key属性和IV属性设置为用于加密的相同值。

SymmetricAlgorithm.IV属性:来自前一个块的信息被混合到加密下一个块的过程中。 因此,两个相同的纯文本块的输出是不同的。 因为该技术使用前一个块来加密下一个块,所以需要初始化向量来加密第一个数据块。 (根据SymmetricAlgorithm.IV属性 MSDN文章)

有效密钥大小为:128,192,256位(根据我的AES方法为字节数组创建多少个字符? )

主体计划

 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; } } 

参考

  1. 为我的AES方法创建一个字节数组的字符数是多少?
  2. 指定的密钥不是此算法的有效大小
  3. 使用AES-256和初始化向量进行加密
  4. Base-64 char数组的长度无效
  5. 在编码方面,UTF8 / UTF16和Base64之间有什么区别

使用加密原语很容易导致实现错误,人们总是这样做,如果可以的话,最好使用高级库 。

我有一个片段 ,我尝试不断审查和更新,这与你正在做的非常接近。 它还对密文进行身份validation,如果攻击者无论如何都可以将选择的密文发送到您的解密实现,我建议对其进行身份validation,还有很多与修改密文有关的辅助通道攻击。

但是,您遇到的问题与填充没有任何关系,如果您的密文与您的密钥和iv不匹配,并且您没有validation您的iv和密文,您通常会得到填充错误(如果这是冒充客户端,它被称为填充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来解密,就像加密一样。