使用C#进行AES解密

时间:2015-07-25 06:08:40

标签: c# security cryptography aes bouncycastle

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

我已将其配置为使用以下方案获取数据

AES(Bouncy Castle)

  • 姓名:PBEWITHSHA256AND128BITAES-CBC-BC
  • 要求:Bouncy Castle API和JCE Unlimited Strength Policy Files
  • 哈希算法:SHA256
  • Hashing Iterations:1000

现在,当我重新阅读配置数据时,我需要在使用之前解密信息,文档提供了有关此主题的以下信息。

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

  • 将Base64字符串转换为字节
  • 剥去前8或16个字节作为盐
  • 保留加密有效负载的剩余字节
  • 使用salt,迭代计数和密码调用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配置为使用以下密码进行加密

  

SimplePassword

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

  

p8C9hAHaoo0F25rMueT0 + u0O6xYVpGIkjHmWqFJmTOvpV8 + cipoDFIUnaOFF5ElQ

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

  

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

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

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

我使用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);
}