У меня есть приложение C #, которое реализует шифрование. Я работаю над добавлением некоторых функций в PHP для работы с этим приложением. Я использую Rijndael Managed шифрование в приложении. Я могу расшифровать строку в PHP без проблем, но когда я пытаюсь зашифровать строку, она не соответствует тому, что было создано в приложении C #. Я просмотрел stackoverflow и перепробовал кучу комбинаций, но, похоже, не могу заставить все работать правильно.
Мой код 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;
Вот где это становится интересным. Я получаю расшифрованную строку очень хорошо (она печатает Джексона), но байтовый массив для нее очень странный. Кажется, что, как исходная строка дополняется, может быть причиной проблемы.
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 # в значительной степени исключено, если у меня нет вспомогательной функции в приложении, которая корректирует значения перед сохранением в базе данных ….
Большое спасибо за любую помощь.
РЕДАКТИРОВАТЬ: Обновлено с решением
Как отметил Кевин, разница между UTF-16 в приложении C # и UTF-8 в PHP. Чтобы решить эту проблему, мне просто нужно было внести небольшое изменение в функцию 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;
}
Причиной появления нулей в массиве является то, что вы используете кодировку Unicode (16 бит на символ) для преобразования исходной строки в массив. Если вы использовали UTF8 или ASCII (8 бит на символ), 0 больше не будут появляться в массиве. Вам просто нужно убедиться, что вы используете одну и ту же кодировку с обеих сторон (для создания массива на отправляющей стороне и для кодирования строки на принимающей стороне). Тогда, пока ваши ключи и капельницы совпадают с обеих сторон, вам будет хорошо идти.
Других решений пока нет …