Я работал над этим некоторое время, и я не знаю много о 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");
У вас здесь множество разных проблем. Проблема, вызывающая проблему невозможности расшифровать данные PHP, зашифрованные в .NET, заключается в том, что в версии PHP вы выполняете substr
на шифротекста до расшифровки. Комментарии в коде указывают на то, что вы удаляете IV, за исключением того, что это, по-видимому, имело значение только в предыдущей версии кода, когда вы (правильно) использовали случайный IV каждый раз — теперь вы просто отбрасываете первые 16 байтов зашифрованного текста, который из-за режима работы портит последующий блок данных.
Другая проблема (хотя и маскируется тем фактом, что вы отбрасываете первые 16 байтов данных открытого текста при дешифровании в .NET) заключается в том, что IV, который вы используете в .NET (16 байтов 0x00
) не совпадает с IV, который вы используете в PHP (16 символов ‘0’ = 16 байт 0x30
).
Я бы предложил вернуться к использованию случайного IV для каждого шифрования и добавить IV к зашифрованному тексту. после шифрование При расшифровке считывайте IV из первых байтов зашифрованного текста, а затем расшифровывайте оставшуюся часть. Это гораздо более безопасно, чем использование статического IV, особенно когда шифруемые данные часто могут быть одинаковыми.
Это выглядит как будто это простая проблема кодировки символов. Ваш код C # получает ASCII-представление вашей строки и шифрует его, но ваш код PHP расшифровывает его и ожидает, что это будет UTF-8.
Попробуйте поменять свой Encoding.ASCII
призывает для Encoding.UTF8
и убедитесь, что ваш crypt.Charset
а также crypt.SetEncodedIV
UTF8, а также