向 C# 发出匹配 PHP 加密
Issue matching PHP encryption to C#
我有一个实现加密的 C# 应用程序。我正在努力在 PHP 中添加一些功能以使用此应用程序。我在应用程序中使用 Rijndael 托管加密。我能够解密 PHP 中的字符串没问题,但是当我尝试加密字符串时,它与在 C# 应用程序中创建的字符串不匹配。我搜索了 Whosebug 并尝试了一堆组合,但似乎无法正常工作。
我加密字符串的C#代码如下:
public static string Encrypt(string plainText, byte[] key, byte[] iv)
{
RijndaelManaged crypto = new RijndaelManaged();
crypto.Key = key;
crypto.IV = iv;
byte[] textBytes = System.Text.Encoding.Unicode.GetBytes(plainText);
ICryptoTransform Encryptor = crypto.CreateEncryptor(crypto.Key, crypto.IV);
MemoryStream mem_stream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(mem_stream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(textBytes, 0, textBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherBytes = mem_stream.ToArray();
mem_stream.Close();
cryptoStream.Close();
string Encrypt_Data = Convert.ToBase64String(CipherBytes);
return Encrypt_Data;
}
在PHP中我使用了下面的代码:
class Encryption {
protected $cipher = MCRYPT_RIJNDAEL_128;
protected $mode = MCRYPT_MODE_CBC;
public function getKey()
{
return implode(array_map('chr', .....);
}
function addPadding($string)
{
$blocksize = mcrypt_get_block_size($this->cipher, $this->mode);
$padding = $blocksize - (strlen($string) % $blocksize);
$string .= str_repeat(chr($padding), $padding);
return $string;
}
function Encrypt($string, $iv)
{
$value = rtrim(base64_encode(mcrypt_encrypt($this->cipher, $this->getKey(), $this->addPadding($string), $this->mode, $iv)));
return $value;
}
function Decrypt($string, $iv)
{
return rtrim(mcrypt_decrypt($this->cipher, $this->getKey(), base64_decode($string), $this->mode, $iv));
}
}
两者使用相同的私钥(一个 32 字节长的字节数组)。我使用现有示例对其进行测试,如下所示:
$iv = hex2bin('B773705230CFADC864401FF2EB1FCF14');
$first = 'Jx7Khz4v+AQE3lUkIQF/SA==';
$enc = new Encryption;
$decrypted = $enc->Decrypt($first, $iv);
print_r(unpack('C*', $decrypted));
print_r(unpack('C*', 'Jackson'));
$encrypted = $enc->Encrypt('Jackson', $iv);
echo 'C# Encrypted: '.$first."\n";
echo 'Decrypted: '.$decrypted."\n";
echo 'PHP Encrypted: '.$encrypted;
这就是有趣的地方。我很好地得到了解密的字符串(它打印出 Jackson),但是它的字节数组非常奇怪。似乎初始字符串的填充方式可能是导致问题的原因。
Array
(
[1] => 74
[2] => 0
[3] => 97
[4] => 0
[5] => 99
[6] => 0
[7] => 107
[8] => 0
[9] => 115
[10] => 0
[11] => 111
[12] => 0
[13] => 110
[14] => 0
[15] => 2
[16] => 2
)
Array
(
[1] => 74
[2] => 97
[3] => 99
[4] => 107
[5] => 115
[6] => 111
[7] => 110
)
C# Encrypted: Jx7Khz4v+AQE3lUkIQF/SA==
Decrypted: Jackson
PHP Encrypted: /qIq5gSWFPbLpGJMkGg+Zw==
这显然与填充有关。我只是不确定为什么每隔一个字节似乎都有 0。我显然在某处遗漏了一些东西。我已经在 c# 中设置了加密,数据已经加密,所以更改 C# 代码几乎是不可能的,除非我在应用程序中有一个辅助函数在存储到数据库之前调整值....
非常感谢您的帮助。
编辑:更新解决方案
正如 Kevin 所指出的,区别在于 C# 应用程序中的 UTF-16 和 PHP 中的 UTF-8。为了解决这个问题,我只需要对 Encrypt 函数做一个小改动,如下所示,将字符串转换为正确的编码:
function Encrypt($string, $iv)
{
$string = iconv('UTF-8', 'UTF-16LE', $string);
$value = rtrim(base64_encode(mcrypt_encrypt($this->cipher, $this->getKey(), $this->addPadding($string), $this->mode, $iv)));
return $value;
}
数组中出现 0 的原因是您使用 Unicode 编码(每个字符 16 位)将源字符串转换为数组。如果您使用 UTF8 或 ASCII(每个字符 8 位),0 将不再出现在数组中。您只需要确保双方都使用相同的编码(在发送方创建数组并在接收方对字符串进行编码)。然后,只要您的密钥和 IV 在两侧都匹配,您就可以开始了。
我有一个实现加密的 C# 应用程序。我正在努力在 PHP 中添加一些功能以使用此应用程序。我在应用程序中使用 Rijndael 托管加密。我能够解密 PHP 中的字符串没问题,但是当我尝试加密字符串时,它与在 C# 应用程序中创建的字符串不匹配。我搜索了 Whosebug 并尝试了一堆组合,但似乎无法正常工作。
我加密字符串的C#代码如下:
public static string Encrypt(string plainText, byte[] key, byte[] iv)
{
RijndaelManaged crypto = new RijndaelManaged();
crypto.Key = key;
crypto.IV = iv;
byte[] textBytes = System.Text.Encoding.Unicode.GetBytes(plainText);
ICryptoTransform Encryptor = crypto.CreateEncryptor(crypto.Key, crypto.IV);
MemoryStream mem_stream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(mem_stream, Encryptor, CryptoStreamMode.Write);
cryptoStream.Write(textBytes, 0, textBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] CipherBytes = mem_stream.ToArray();
mem_stream.Close();
cryptoStream.Close();
string Encrypt_Data = Convert.ToBase64String(CipherBytes);
return Encrypt_Data;
}
在PHP中我使用了下面的代码:
class Encryption {
protected $cipher = MCRYPT_RIJNDAEL_128;
protected $mode = MCRYPT_MODE_CBC;
public function getKey()
{
return implode(array_map('chr', .....);
}
function addPadding($string)
{
$blocksize = mcrypt_get_block_size($this->cipher, $this->mode);
$padding = $blocksize - (strlen($string) % $blocksize);
$string .= str_repeat(chr($padding), $padding);
return $string;
}
function Encrypt($string, $iv)
{
$value = rtrim(base64_encode(mcrypt_encrypt($this->cipher, $this->getKey(), $this->addPadding($string), $this->mode, $iv)));
return $value;
}
function Decrypt($string, $iv)
{
return rtrim(mcrypt_decrypt($this->cipher, $this->getKey(), base64_decode($string), $this->mode, $iv));
}
}
两者使用相同的私钥(一个 32 字节长的字节数组)。我使用现有示例对其进行测试,如下所示:
$iv = hex2bin('B773705230CFADC864401FF2EB1FCF14');
$first = 'Jx7Khz4v+AQE3lUkIQF/SA==';
$enc = new Encryption;
$decrypted = $enc->Decrypt($first, $iv);
print_r(unpack('C*', $decrypted));
print_r(unpack('C*', 'Jackson'));
$encrypted = $enc->Encrypt('Jackson', $iv);
echo 'C# Encrypted: '.$first."\n";
echo 'Decrypted: '.$decrypted."\n";
echo 'PHP Encrypted: '.$encrypted;
这就是有趣的地方。我很好地得到了解密的字符串(它打印出 Jackson),但是它的字节数组非常奇怪。似乎初始字符串的填充方式可能是导致问题的原因。
Array
(
[1] => 74
[2] => 0
[3] => 97
[4] => 0
[5] => 99
[6] => 0
[7] => 107
[8] => 0
[9] => 115
[10] => 0
[11] => 111
[12] => 0
[13] => 110
[14] => 0
[15] => 2
[16] => 2
)
Array
(
[1] => 74
[2] => 97
[3] => 99
[4] => 107
[5] => 115
[6] => 111
[7] => 110
)
C# Encrypted: Jx7Khz4v+AQE3lUkIQF/SA==
Decrypted: Jackson
PHP Encrypted: /qIq5gSWFPbLpGJMkGg+Zw==
这显然与填充有关。我只是不确定为什么每隔一个字节似乎都有 0。我显然在某处遗漏了一些东西。我已经在 c# 中设置了加密,数据已经加密,所以更改 C# 代码几乎是不可能的,除非我在应用程序中有一个辅助函数在存储到数据库之前调整值....
非常感谢您的帮助。
编辑:更新解决方案
正如 Kevin 所指出的,区别在于 C# 应用程序中的 UTF-16 和 PHP 中的 UTF-8。为了解决这个问题,我只需要对 Encrypt 函数做一个小改动,如下所示,将字符串转换为正确的编码:
function Encrypt($string, $iv)
{
$string = iconv('UTF-8', 'UTF-16LE', $string);
$value = rtrim(base64_encode(mcrypt_encrypt($this->cipher, $this->getKey(), $this->addPadding($string), $this->mode, $iv)));
return $value;
}
数组中出现 0 的原因是您使用 Unicode 编码(每个字符 16 位)将源字符串转换为数组。如果您使用 UTF8 或 ASCII(每个字符 8 位),0 将不再出现在数组中。您只需要确保双方都使用相同的编码(在发送方创建数组并在接收方对字符串进行编码)。然后,只要您的密钥和 IV 在两侧都匹配,您就可以开始了。