【发布时间】:2017-03-31 13:54:51
【问题描述】:
我有一个 PHP 应用程序使用 openSSL 将带有 Base64 编码的 AES-256-CBC 加密字符串发送到 .NET 应用程序。我启动了解密方法,但是当我尝试实际解密数据时总是出错。错误状态为“填充无效且无法删除”。我在这里做错了什么?
PHP函数生成的加密Base64值是: p07cNwcvcYLxvYHCUsmZqKYr40IXXYjEHr7r+JdgXiJT5/wpDSDmr48JLOXyNEL7
关键是: M2AZULUALPHA
盐是: TripBuilder2017x
PHP函数是:
function encrypt($text) {
$key = "M2AZULUALPHA";
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$padding = $block - (strlen($text) % $block);
$text .= str_repeat(chr($padding), $padding);
$crypttext = openssl_encrypt($text,'aes-256-cbc', $key, OPENSSL_RAW_DATA, 'TripBuilder2017x');
return base64_encode($crypttext);
}
.NET 解密函数:
private string Decrypt(string cipherText)
{
string EncryptionKey = "M2AZULUALPHA";
byte[] saltArray = Encoding.ASCII.GetBytes("TripBuilder2017x");
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, saltArray);
encryptor.Mode = CipherMode.CBC;
encryptor.BlockSize = 128;
encryptor.KeySize = 256;
encryptor.Padding = PaddingMode.PKCS7;
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
更新 我使用了一个在线 openSSL 解密工具,输入了我的 IV、Key 和 base64 文本。它生成了正确的字符串,但字符串中有一些奇怪的块。
更新 2 这是更新的 PHP 代码。我也将密钥大小增加到 16 个字节。我仍然收到同样的错误。
$key = "M2AZULUALPHAECHO";
$salt = "TripBuilder2017x";
$mode = "aes-256-cbc";
$text = "BrassMonkey";
function encrypt($text,$key,$salt,$mode) {
return base64_encode(encryptplain($text,$key,$salt,$mode));
}
function encryptplain($text,$key,$salt,$mode) {
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$padding = $block - (strlen($text) % $block);
$text .= str_repeat(chr($padding), $padding);
$crypttext = openssl_encrypt($text, $mode, $key, 1, $salt);
return ($crypttext);
}
更新 3:我的 .NET 代码
private string Decrypt(string cipherText)
{
string EncryptionKey = "M2AZULUALPHAECHO";
byte[] saltArray = Encoding.ASCII.GetBytes("TripBuilder2017x");
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
encryptor.Mode = CipherMode.CBC;
encryptor.BlockSize = 128;
encryptor.KeySize = 256;
encryptor.Padding = PaddingMode.PKCS7;
encryptor.Key = Encoding.ASCII.GetBytes(EncryptionKey);
encryptor.IV = saltArray;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
【问题讨论】:
-
我遇到了类似的问题,我的结论是 openssl 不会返回任何二进制数据 :(,我改用 mcrypt
-
我在使用 MCrypt 时遇到了同样的问题,这就是我尝试 OpenSSL 的原因。由于我遇到了同样的错误,我觉得这与我分配值的属性有关。
-
我不推荐使用 mcrypt,因为这是当前 PHP 版本中已弃用的函数。在线查看器中的块可能是您的浏览器/站点使用的字符集中不可用的字符的原因。
-
mcrypt_get_block_size 以字节为单位返回块大小,而 Aes 块大小需要位。我猜这可能是你的不匹配。
-
@DempseyLawrence 我们甚至需要获取块大小吗?OpenSSL 中是否有等效的方法?
标签: c# php encryption cryptography