无法在 C# bouncycastle 和 PHP openssl 之间交换 AES-256-CBC/PKCS7
Unable to exchange AES-256-CBC/PKCS7 between C# bouncycastle and PHP openssl
所以我在 C# 和 PHP 中有以下代码,到目前为止,双方的结果并不一致。对于 C#,我使用的是充气城堡 API,对于 PHP,我使用的是 openSSL。可以肯定的是,我还在 C# 中使用 Microsoft Crypto Library 加密了相同的东西,并且我得到了相同的密文,但当它们与 PHP 交换时却不是。
C#
public const string AES_ALGORITHM = "AES/CBC/PKCS7";
public const string CRYPTO_ALGORITHM = "AES";
public AESController(string key) {
encryptionKey = Convert.FromBase64String(key);
}
public string encrypt(string plainText, byte[] iv) {
string cipherText = "";
//setting up AES Key
KeyParameter aesKeyParam = ParameterUtilities.CreateKeyParameter(CRYPTO_ALGORITHM, encryptionKey);
// Setting up the Initialization Vector. IV is used for encrypting the first block of input message
ParametersWithIV aesIVKeyParam = new ParametersWithIV(aesKeyParam, iv);
// Create the cipher object for AES algorithm using GCM mode and NO padding
IBufferedCipher cipher = CipherUtilities.GetCipher(AES_ALGORITHM);
cipher.Init(true, aesIVKeyParam);
byte[] output = cipher.DoFinal(Encoding.UTF8.GetBytes(plainText));
cipherText = Convert.ToBase64String(output);
return cipherText;
}
public string decrypt(string cipherText, byte[] iv) {
string plainText = "";
//setting up AES Key
KeyParameter aesKeyParam = ParameterUtilities.CreateKeyParameter(CRYPTO_ALGORITHM, encryptionKey);
// Setting up the Initialization Vector. IV is used for encrypting the first block of input message
ParametersWithIV aesIVKeyParam = new ParametersWithIV(aesKeyParam, iv);
// Create the cipher object for AES algorithm using GCM mode and NO padding
IBufferedCipher cipher = CipherUtilities.GetCipher(AES_ALGORITHM);
cipher.Init(false, aesIVKeyParam);
byte[] output = cipher.DoFinal(Convert.FromBase64String(cipherText));
plainText = Encoding.UTF8.GetString(output);
return plainText;
}
static void Main(string[] args) {
AESController aes = new AESController("OXzN4fxHHgcKtAt/SJ4UWtNiQlzno7II1gIBs24CWpY=");
byte[] iv = Base64.Decode("fdL8sKmhC8YIrYHMzoJJvQ==");
string encryptedText = "TESTING123";
string cipherText = aes.encrypt(encryptedText, iv);
Console.Out.WriteLine("IV: " + Encoding.UTF8.GetString(Base64.Encode(iv)));
Console.Out.WriteLine("Plain Text:"+aes.decrypt(cipherText, iv));
Console.Out.WriteLine("Cipher Text:" + cipherText);
Console.In.ReadLine();
}
然后 PHP:
$key = "OXzN4fxHHgcKtAt/SJ4UWtNiQlzno7II1gIBs24CWpY=";
$iv = base64_decode("fdL8sKmhC8YIrYHMzoJJvQ==");
//$iv = openssl_random_pseudo_bytes(16);
//$cipherText = "YMdJ0mdWZ+p50krLzhyI0Q==";
$plainText = "TESTING123";
$decrypted = openssl_encrypt($plainText, "aes-256-cbc", $key, 0, $iv);
var_dump($decrypted);
所以,来自 C# bouncycastle 的密文是:
EnOtpv4fOGiAKMzXXJMYBA==
来自PHP的密文是:
Cs+f7a/DBEGma7iQ/PQVLw==
如果我将那个 c# 密文取到 PHP,解密结果是:bool(False)
(加密失败)
最后,如果在PHP中,我将填充更改为OPENSSL_ZERO_PADDING,并从C#解密密文,结果是:
���_�X�GmNSlZx�
据我所知,两者的密钥和IV相同(均为BASE64字符串),加密后的结果具有相同的长度(这解释了密文末尾的两个==。是有什么我想念的,或者我需要为 openssl 库做一些特别的事情吗?谢谢。
与 OpenSSL 命令行工具不同,PHP 的 openssl 函数需要原始输入,而不是 Base64 编码的输入。
在您的 PHP 代码中,您尚未对密钥进行 Base64 解码。
所以我在 C# 和 PHP 中有以下代码,到目前为止,双方的结果并不一致。对于 C#,我使用的是充气城堡 API,对于 PHP,我使用的是 openSSL。可以肯定的是,我还在 C# 中使用 Microsoft Crypto Library 加密了相同的东西,并且我得到了相同的密文,但当它们与 PHP 交换时却不是。
C#
public const string AES_ALGORITHM = "AES/CBC/PKCS7";
public const string CRYPTO_ALGORITHM = "AES";
public AESController(string key) {
encryptionKey = Convert.FromBase64String(key);
}
public string encrypt(string plainText, byte[] iv) {
string cipherText = "";
//setting up AES Key
KeyParameter aesKeyParam = ParameterUtilities.CreateKeyParameter(CRYPTO_ALGORITHM, encryptionKey);
// Setting up the Initialization Vector. IV is used for encrypting the first block of input message
ParametersWithIV aesIVKeyParam = new ParametersWithIV(aesKeyParam, iv);
// Create the cipher object for AES algorithm using GCM mode and NO padding
IBufferedCipher cipher = CipherUtilities.GetCipher(AES_ALGORITHM);
cipher.Init(true, aesIVKeyParam);
byte[] output = cipher.DoFinal(Encoding.UTF8.GetBytes(plainText));
cipherText = Convert.ToBase64String(output);
return cipherText;
}
public string decrypt(string cipherText, byte[] iv) {
string plainText = "";
//setting up AES Key
KeyParameter aesKeyParam = ParameterUtilities.CreateKeyParameter(CRYPTO_ALGORITHM, encryptionKey);
// Setting up the Initialization Vector. IV is used for encrypting the first block of input message
ParametersWithIV aesIVKeyParam = new ParametersWithIV(aesKeyParam, iv);
// Create the cipher object for AES algorithm using GCM mode and NO padding
IBufferedCipher cipher = CipherUtilities.GetCipher(AES_ALGORITHM);
cipher.Init(false, aesIVKeyParam);
byte[] output = cipher.DoFinal(Convert.FromBase64String(cipherText));
plainText = Encoding.UTF8.GetString(output);
return plainText;
}
static void Main(string[] args) {
AESController aes = new AESController("OXzN4fxHHgcKtAt/SJ4UWtNiQlzno7II1gIBs24CWpY=");
byte[] iv = Base64.Decode("fdL8sKmhC8YIrYHMzoJJvQ==");
string encryptedText = "TESTING123";
string cipherText = aes.encrypt(encryptedText, iv);
Console.Out.WriteLine("IV: " + Encoding.UTF8.GetString(Base64.Encode(iv)));
Console.Out.WriteLine("Plain Text:"+aes.decrypt(cipherText, iv));
Console.Out.WriteLine("Cipher Text:" + cipherText);
Console.In.ReadLine();
}
然后 PHP:
$key = "OXzN4fxHHgcKtAt/SJ4UWtNiQlzno7II1gIBs24CWpY=";
$iv = base64_decode("fdL8sKmhC8YIrYHMzoJJvQ==");
//$iv = openssl_random_pseudo_bytes(16);
//$cipherText = "YMdJ0mdWZ+p50krLzhyI0Q==";
$plainText = "TESTING123";
$decrypted = openssl_encrypt($plainText, "aes-256-cbc", $key, 0, $iv);
var_dump($decrypted);
所以,来自 C# bouncycastle 的密文是:
EnOtpv4fOGiAKMzXXJMYBA==
来自PHP的密文是:
Cs+f7a/DBEGma7iQ/PQVLw==
如果我将那个 c# 密文取到 PHP,解密结果是:bool(False) (加密失败)
最后,如果在PHP中,我将填充更改为OPENSSL_ZERO_PADDING,并从C#解密密文,结果是:
���_�X�GmNSlZx�
据我所知,两者的密钥和IV相同(均为BASE64字符串),加密后的结果具有相同的长度(这解释了密文末尾的两个==。是有什么我想念的,或者我需要为 openssl 库做一些特别的事情吗?谢谢。
与 OpenSSL 命令行工具不同,PHP 的 openssl 函数需要原始输入,而不是 Base64 编码的输入。
在您的 PHP 代码中,您尚未对密钥进行 Base64 解码。