使用C#进行AES解密
AES Decryption Using C#
我正在使用名为 Zuul 的基于 Java 的配置管理工具,它支持使用各种加密方案对敏感配置信息进行加密。
我已将其配置为对我的数据使用以下方案
AES(充气城堡)
- 名称:PBEWITHSHA256AND128BITAES-CBC-BC
- 要求:Bouncy Castle API 和 JCE Unlimited Strength 策略文件
- 哈希算法:SHA256
- 哈希迭代:1000
现在,当读回我的配置数据时,我需要先解密信息才能使用它,文档提供了以下有关此主题的信息。
Jasypt(以及 Zuul)生成的加密值以盐为前缀(通常为 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 配置为使用以下密码进行加密
SimplePassword
现在我有一个 Zuul 给我的加密字符串,我需要解密它
p8C9hAHaoo0F25rMueT0+u0O6xYVpGIkjHmWqFJmTOvpV8+cipoDFIUnaOFF5ElQ
当我尝试使用上面的代码解密这个字符串时,出现以下异常
System.Security.Cryptography.CryptographicException : Padding is invalid and cannot be removed.
正如我之前提到的,我对这个主题的了解是有限的,我无法弄清楚文档中提供的信息是否不够,如果我在编写解密例程时做错了什么,或者我应该也可以使用充气城堡进行解密。
如有任何帮助,我们将不胜感激。
根据 Zuul 文档,他们从 password/salt 派生密钥和 iv。
所以你应该导出 256+128 位(即 48 字节),并使用前 32 个字节作为密钥,接下来的 16 个字节作为 IV。
这应该在一次操作中完成,而不是随后调用 key.DeriveBytes.
我改用 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);
}
我正在使用名为 Zuul 的基于 Java 的配置管理工具,它支持使用各种加密方案对敏感配置信息进行加密。
我已将其配置为对我的数据使用以下方案
AES(充气城堡)
- 名称:PBEWITHSHA256AND128BITAES-CBC-BC
- 要求:Bouncy Castle API 和 JCE Unlimited Strength 策略文件
- 哈希算法:SHA256
- 哈希迭代:1000
现在,当读回我的配置数据时,我需要先解密信息才能使用它,文档提供了以下有关此主题的信息。
Jasypt(以及 Zuul)生成的加密值以盐为前缀(通常为 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 配置为使用以下密码进行加密
SimplePassword
现在我有一个 Zuul 给我的加密字符串,我需要解密它
p8C9hAHaoo0F25rMueT0+u0O6xYVpGIkjHmWqFJmTOvpV8+cipoDFIUnaOFF5ElQ
当我尝试使用上面的代码解密这个字符串时,出现以下异常
System.Security.Cryptography.CryptographicException : Padding is invalid and cannot be removed.
正如我之前提到的,我对这个主题的了解是有限的,我无法弄清楚文档中提供的信息是否不够,如果我在编写解密例程时做错了什么,或者我应该也可以使用充气城堡进行解密。
如有任何帮助,我们将不胜感激。
根据 Zuul 文档,他们从 password/salt 派生密钥和 iv。 所以你应该导出 256+128 位(即 48 字节),并使用前 32 个字节作为密钥,接下来的 16 个字节作为 IV。 这应该在一次操作中完成,而不是随后调用 key.DeriveBytes.
我改用 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);
}