Не могу понять, почему PHP для C # .NET не будет симметрично шифровать / дешифровать

Я работал над этим некоторое время, и я не знаю много о PHP или C #. Мы создаем приложение, которое использует шифрование в режиме AES 128 CBC для хранения вещей в базе данных. Одна часть — это PHP и JS, другая — C # .NET WPF.

Человек, который написал PHP, использовал библиотеку Mcrypt для шифрования / дешифрования. Я использую библиотеку Chilkat для шифрования / дешифрования. В Chilkat был пример C # по умолчанию, который должен имитировать PHP Mcrypt.

В настоящее время я могу симметрично шифровать / дешифровать вещи в .Net, а .Net может расшифровывать что угодно из PHP. Однако сторона PHP не может расшифровать все, что я шифрую в базе данных со стороны .Net.

Я сузил хотя бы часть проблем кодирования, но я не уверен, как это исправить. Схема дешифрования на стороне PHP обычно дешифрует в ASCII, но для вещей, которые я посылаю, она дешифрует в UTF-8. Я пытался расшифровать его, а затем кодировать из UTF-8 в ASCII безрезультатно.

Я покажу вам входы / выходы и функции. IV устанавливается на 16 ASCII 0, чтобы помочь моей отладке, хотя это не должно иметь большого значения.

вход из .Net в mcrypt_encrypt func: строка «1220» выход: 3tRIG7qUxUsU7WoXDybRRcdQRobOfeFGtQ438V7XRD8 =
Ввод параметров в базу данных = ‘как указано выше’

ввод стороны PHP расшифровать func = 3tRIG7qUxUsU7WoXDybRRcdQRobOfeFGtQ438V7XRD8 = ‘то же, что и выше’

вывод функции mcrypt_decrypt = J {$ Z ‘? u’ iconv говорит, что кодировка utf-8 ‘

Попросите что-нибудь еще, и я получу это, если это помогло бы. Я уверен, что это какая-то глупая легкая проблема, которую я не вижу.

Сторона PHP — если это имеет значение, кодировка PHP установлена ​​в UTF-8

function encrypt($input)
{

$this->iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);

/*No longer using random iv :(
$this->iv = mcrypt_create_iv($this->iv_size, MCRYPT_RAND);*/

//use 16 zeros
$this->iv = '0000000000000000';

$encrypted = $this->iv .mcrypt_encrypt(MCRYPT_RIJNDAEL_128, KEY, $input, MODE, $this->iv);

//Finally encode this as base 64, see http://php.net/manual/en/function.base64-encode.php
$encrypted = base64_encode($encrypted);

return $encrypted;
}function decrypt($input)
{
/*Get our message back!!!
First decode the base 64 string. Note, de/encoding bas 64 != encryption*/
$ciphertext_dec = base64_decode($input);

//Get the iv back out for decryption
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);

//$iv_dec = substr($ciphertext_dec, 0, $iv_size);*/
$iv_dec = '0000000000000000';

//Now get the text of encrypted message (all but the iv in front)
$ciphertext_dec = substr($ciphertext_dec, $iv_size);

//Now decrypt the message
$plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, KEY, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

//Test
//test
//$plaintext_dec = iconv("UTF-8", "ASCII", $plaintext_dec);
//echo mb_detect_encoding($plaintext_dec, "auto");
//echo $plaintext_dec;

/*However, we might now have blank space @ end of output b/c
remember we de/encrypt via block, so a 10 char long message
could be padded to 16 char long with blank spaces. Get rid of those.*/
$plaintext_dec = trim($plaintext_dec);

//return so we can compare to, i.e., original input
return $plaintext_dec;
}

.NET C #

    public string mcrypt_encrypt(string plainText)
{
plainText = Encoding.ASCII.GetString(crypt.IV) + plainText;
byte[] myText = Encoding.ASCII.GetBytes(plainText);

//  Do 128-bit AES encryption:
byte[] cipherText = crypt.EncryptBytes(myText);

return Convert.ToBase64String(cipherText);
}

public string mcrypt_decrypt(string cipher_text)
{

byte[] cipher_dec = Convert.FromBase64String(cipher_text);

byte[] plainBytes = crypt.DecryptBytes(cipher_dec);

string decrypted = Encoding.ASCII.GetString(plainBytes);

string plain_text = decrypted.Substring(16, decrypted.Length - 16);

return plain_text.TrimEnd('\0');
}

C # Chilkat init:
// AES также известен как Rijndael.

          crypt.CryptAlgorithm = "aes";

//  CipherMode may be "ecb" or "cbc"crypt.CipherMode = "cbc";

//  KeyLength may be 128, 192, 256
crypt.KeyLength = 128;

//  Pad with NULL bytes (PHP pads with NULL bytes)
crypt.PaddingScheme = 3;

//  EncodingMode specifies the encoding of the output for
//  encryption, and the input for decryption.
//  It may be "hex", "url", "base64", or "quoted-printable".
crypt.EncodingMode = "hex";

//  The secret key must equal the size of the key.  For
//  256-bit encryption, the binary secret key is 32 bytes.
//  For 128-bit encryption, the binary secret key is 16 bytes.
string keyAscii = @"&=*FS6wksG@Zs3qG";
crypt.SecretKey = Encoding.UTF8.GetBytes(keyAscii);
crypt.Charset = "ASCII";

crypt.SetEncodedIV("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", "ascii");

1

Решение

У вас здесь множество разных проблем. Проблема, вызывающая проблему невозможности расшифровать данные PHP, зашифрованные в .NET, заключается в том, что в версии PHP вы выполняете substr на шифротекста до расшифровки. Комментарии в коде указывают на то, что вы удаляете IV, за исключением того, что это, по-видимому, имело значение только в предыдущей версии кода, когда вы (правильно) использовали случайный IV каждый раз — теперь вы просто отбрасываете первые 16 байтов зашифрованного текста, который из-за режима работы портит последующий блок данных.

Другая проблема (хотя и маскируется тем фактом, что вы отбрасываете первые 16 байтов данных открытого текста при дешифровании в .NET) заключается в том, что IV, который вы используете в .NET (16 байтов 0x00) не совпадает с IV, который вы используете в PHP (16 символов ‘0’ = 16 байт 0x30).

Я бы предложил вернуться к использованию случайного IV для каждого шифрования и добавить IV к зашифрованному тексту. после шифрование При расшифровке считывайте IV из первых байтов зашифрованного текста, а затем расшифровывайте оставшуюся часть. Это гораздо более безопасно, чем использование статического IV, особенно когда шифруемые данные часто могут быть одинаковыми.

2

Другие решения

Это выглядит как будто это простая проблема кодировки символов. Ваш код C # получает ASCII-представление вашей строки и шифрует его, но ваш код PHP расшифровывает его и ожидает, что это будет UTF-8.

Попробуйте поменять свой Encoding.ASCII призывает для Encoding.UTF8 и убедитесь, что ваш crypt.Charset а также crypt.SetEncodedIV UTF8, а также

1