简体   繁体   中英

AES Decryption Using C#

I am using a Java based configuration management tool called Zuul which supports encrypting sensitive configuration information using various encryption schemes.

I have configured it to use below scheme for my data

AES (Bouncy Castle)

  • Name: PBEWITHSHA256AND128BITAES-CBC-BC
  • Requirements: Bouncy Castle API and JCE Unlimited Strength Policy Files
  • Hashing Algorithm: SHA256
  • Hashing Iterations: 1000

Now when reading my configuration data back, I need to decrypt the information before I can use it and the documentation provides below information around this topic.

The encrypted values produced by Jasypt (and thus Zuul) are are prefixed with the salt (usually 8 or 16 bytes depending on the algorithm requirements). They are then Base64 encoded. Decrypting the results goes something like this:

  • Convert the Base64 string to bytes
  • Strip off the first 8 or 16 bytes as the salt
  • Keep the remaining bytes for the encrypted payload
  • Invoke the KDF function with the salt, iteration count and the password to create the secret key.
  • Use the secret key to decrypt the encrypted payload

More details here: Zull Encryption wiki

Based on above details, I have written below code (and my knowledge around security is very limited)

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

I configured Zuul to use below password for the encryption

SimplePassword

And now I have an encrypted string given to me by Zuul and I need to decrypt it

p8C9hAHaoo0F25rMueT0+u0O6xYVpGIkjHmWqFJmTOvpV8+cipoDFIUnaOFF5ElQ

When I try to decrypt this string using above code, I get below exception

System.Security.Cryptography.CryptographicException : Padding is invalid and cannot be removed.

As I mentioned earlier, my knowledge around this topic is limited and I am not able to figure out if the information provided in the documentation is not enough, if I am doing something wrong while writing the decryption routine or should I be using bouncy castle for decryption as well.

Any help with this will be much appreciated.

According to Zuul documentation they are deriving both key and iv from the password/salt. So you should derive 256+128 bits (ie 48 bytes), and use first 32 bytes as the key, and next 16 bytes as IV. And this should be done in one operation, not as consequent calls to key.DeriveBytes.

I resorted to Bouncy Castle for decryption instead since that is used by Zuul as well.

Here is the code that works

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM