【问题标题】:AES Decryption Using C#使用 C# 进行 AES 解密
【发布时间】:2015-07-25 06:08:39
【问题描述】:

我正在使用基于 Java 的配置管理工具 Zuul,它支持使用各种加密方案对敏感配置信息进行加密。

我已将其配置为对我的数据使用以下方案

AES(充气城堡)

  • 名称:PBEWITHSHA256AND128BITAES-CBC-BC
  • 要求:Bouncy Castle API 和 JCE 无限强度策略文件
  • 哈希算法:SHA256
  • 哈希迭代次数:1000

现在在读回我的配置数据时,我需要先解密信息才能使用它,并且文档提供了有关此主题的以下信息。

Jasypt(以及 Zuul)生成的加密值以 salt 为前缀(通常为 8 或 16 个字节,具体取决于算法要求)。然后对它们进行 Base64 编码。解密结果是这样的:

  • 将 Base64 字符串转换为字节
  • 去掉前 8 或 16 个字节作为盐
  • 保留加密负载的剩余字节
  • 使用盐、迭代计数和密码调用 KDF 函数以创建密钥。
  • 使用密钥解密加密的有效载荷

更多详情:Zull Encryption wiki

基于以上细节,我编写了以下代码(我对安全性的了解非常有限)

public static string Decrypt(string cipher, string password)
{
   const int saltLength = 16;
   const int iterations = 1000;

   byte[] cipherBytes = Convert.FromBase64String(cipher);
   byte[] saltBytes = cipherBytes.Take(saltLength).ToArray();
   byte[] encryptedBytes = cipherBytes.Skip(saltLength).ToArray();

   Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, saltBytes, iterations);
   byte[] keyBytes = key.GetBytes(16);

   AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider();
   aesAlg.KeySize = 256;
   aesAlg.BlockSize = 128;

   aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
   aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8);

   ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
   MemoryStream msDecrypt = new MemoryStream(encryptedBytes);
   CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
   StreamReader srDecrypt = new StreamReader(csDecrypt);

   return srDecrypt.ReadToEnd();
}

我将 Zuul 配置为使用以下密码进行加密

简单密码

现在我有一个 Zuul 给我的加密字符串,我需要解密它

p8C9hAHaoo0F25rMueT0+u0O6xYVpGIkjHmWqFJmTOvpV8+cipoDFIunaOFF5ElQ

当我尝试使用上面的代码解密这个字符串时,我得到以下异常

System.Security.Cryptography.CryptographicException : 填充无效且无法移除。

正如我之前提到的,我对这个主题的了解有限,我无法弄清楚文档中提供的信息是否不够,我在编写解密例程时是否做错了,或者我应该使用充气城堡也可以解密。

对此的任何帮助将不胜感激。

【问题讨论】:

    标签: c# security cryptography aes bouncycastle


    【解决方案1】:

    根据 Zuul 文档,他们从密码/盐中派生密钥和 iv。 所以你应该派生 256+128 位(即 48 字节),并使用前 32 字节作为密钥,接下来的 16 字节作为 IV。 这应该在一个操作中完成,而不是随后调用 key.DeriveBytes。

    【讨论】:

    • 感谢您的回复 Nickolay,现在我明白了 Key 和 Block 大小的重要性。我根据您的建议更新了代码,但仍然出现相同的错误。下面突出显示的是我更改的行 Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, saltBytes, iterations); byte[] keyBytes = key.GetBytes(48); AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider(); aesAlg.KeySize = 256; aesAlg.BlockSize = 128; aesAlg.Key = keyBytes.Take(aesAlg.KeySize / 8).ToArray(); aesAlg.IV = keyBytes.Skip(aesAlg.KeySize / 8).ToArray(); b>
    • 接下来尝试将填充设置为 None 并查看解密是否产生看起来像正确数据的东西。
    • 感谢您的帮助 Nickolay,我已通过添加此行 aesAlg.Padding = PaddingMode.None; 将填充设置为无,这不会导致我的代码再失败,但解密后的值是一些随机字符:(
    • 好的,我现在才发现的下一件事是 Rfc2898DeriveBytes 使用 SHA1,而您显然需要 SHA256。并且请检查加密模式,如果它在 AesCryptoServiceProvider 中默认为 CBC。
    • 你是对的 Nickolay,但是我无法找到使用 SHA256 派生密钥的方法。我已将代码更改为使用 Bouncy Castle,并且一切正常。我也会贴出代码供大家参考。感谢所有帮助和建议。
    【解决方案2】:

    我求助于 Bouncy Castle 进行解密,因为 Zuul 也使用它。

    这是有效的代码

    public static string Decrypt(string cipher, string password)
    {
       const int saltLength = 16;
       const int iterations = 1000;
       const string algSpec = "AES/CBC/NoPadding";
       const string algName = "PBEWITHSHA256AND128BITAES-CBC-BC";
    
       byte[] cipherBytes = Convert.FromBase64String(cipher);
       byte[] saltBytes = cipherBytes.Take(saltLength).ToArray();
       byte[] encryptedBytes = cipherBytes.Skip(saltLength).ToArray();
       char[] passwordChars = password.ToCharArray();
    
       Asn1Encodable defParams = PbeUtilities.GenerateAlgorithmParameters(algName, saltBytes, iterations);
       IWrapper wrapper = WrapperUtilities.GetWrapper(algSpec);
       ICipherParameters parameters = PbeUtilities.GenerateCipherParameters(algName, passwordChars, defParams);
       wrapper.Init(false, parameters);
    
       byte[] keyText = wrapper.Unwrap(encryptedBytes, 0, encryptedBytes.Length);
    
       return Encoding.Default.GetString(keyText);
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-14
      • 1970-01-01
      • 2011-01-31
      相关资源
      最近更新 更多