Значение шифрования Mcrypt js отличается от значения, полученного с помощью PHP mcrypt/Mcrypt JS decrypt, не работает для символов UTF-8

Я пытаюсь внедрить технологию шифрования/дешифрования mcrypt как на сервере, так и на PHP и на стороне клиента. Я пытаюсь использовать библиотеку mcrypt.js на данный момент как:

<?php 
$key = 'testtesttesttesttesttesttesttest';

function string_encrypt($string, $key) {
    $crypted_text = mcrypt_encrypt(
                        MCRYPT_RIJNDAEL_128, 
                        $key, 
                        $string, 
                        MCRYPT_MODE_ECB
                    );
    return base64_encode($crypted_text);
}

function string_decrypt($encrypted_string, $key) {
    $decrypted_text = mcrypt_decrypt(
                        MCRYPT_RIJNDAEL_128, 
                        $key, 
                        base64_decode($encrypted_string), 
                        MCRYPT_MODE_ECB
                    );
    return trim($decrypted_text);
}

echo 'Provided Text:    '.$test_str = 'This is test message.';
echo '<br />';
echo 'Encyrpted Value:  '.$enc_str = string_encrypt($test_str, $key);   
echo '<br />';
echo 'Decrypted Value:  '.string_decrypt($enc_str, $key);                               
echo '<br />';
?>

<script src='rijndael.js'></script>
<script src='mcrypt.js'></script>
<script src='base64v1_0.js'></script>

<script lang='javascript'>
    var enc_str = mcrypt.Encrypt('<?php echo $test_str ?>','');
    enc_str = B64.encode(enc_str);
    alert(enc_str); 
    // I don't get this same as encypted PHP text. i.e. $enc_str
    var dec_str = B64.decode('<?php echo $enc_str ?>');
    alert(mcrypt.Decrypt(dec_str,'')); 
    // I don't get this same as decypted PHP text. 
    // i.e. string_decrypt($enc_str)
</script>

Я использовал эти следующие частные vars в библиотеке mcrypt.js.

 var cMode='ecb';
 var cCipher='rijndael-256';
 var cKey='testtesttesttesttesttesttesttest'; 
 //I am providing the same key

Как я уже отмечал выше, почему он enc_str не равен $enc_str и почему он mcrypt.Decrypt('<?php echo $enc_str ?>', '') не равен string_decrypt($enc_str, $key)?



Обновленный вопрос:

Я пробовал кодирование/декодирование base64 и даже hex2bin/bin2hex для анализа этих строк, но эти два результата дали следующие результаты:


Использование Hex2bin/Bin2hex

Результат PHP:

Provided Text: This is test message.
Encyrpted Value: a51e970427ec8f666a5684cc1712ad03b29889cc10f4ccbf55733564d11c0386
Decrypted Value: This is test message.

Результат JS:

Provided Text:This is test message.
Mcrypted value:¥'ìfjVÌ­²ÌôÌ¿Us5dÑ
Encyrpted Value:a51e970427ec8f666a5684cc1712ad03b29889cc10f4ccbf55733564d11c0386
After Hex to Bin Text:¥'ìfjVÌ­²ÌôÌ¿Us5dÑ
Decrypted Value:This is test message.�����������
/*These diamond with question mark is produced while decypting the value.*/

Использование Base64 encode/decode:

Результат PHP:

Provided Text: This is test message.
Mcrypt encrypted value : ¥—'ìfjV„Ì­²˜‰ÌôÌ¿Us5dц
/*
 Here mcrypted value provided by JS and PHP is different
 That is causing to produce different value at two ends
*/
Encyrpted Value: pR6XBCfsj2ZqVoTMFxKtA7KYicwQ9My/VXM1ZNEcA4Y=
Decrypted Value: This is test message.

Результат JS:

Provided Text:This is test message.
Mcrypted value:¥'ìfjVÌ­²ÌôÌ¿Us5dÑ
Encyrpted Value:wqUewpcEJ8Oswo9malbChMOMFxLCrQPCssKYwonDjBDDtMOMwr9VczVkw5EcA8KG
After Base64 Decode:¥'ìfjVÌ­²ÌôÌ¿Us5dÑ���
Decrypted Value:This is test message.�����������bFaêF«+JéÓ!ÆÖ

И в обоих случаях содержимое UTf-8 не может быть расшифровано в конце JS.


* Ссылки: *

Mcrypt JS library

Base64 JS library

+6
источник поделиться
2 ответа

Основная проблема заключается в том, что ваши функции string_encrypt и string_decrypt PHP не имеют доступа к переменной $key, поэтому для ключа шифрования mcrypt_encrypt используется \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0. См. этот вопрос для объяснения. PHP должен сообщить уведомление о том, что key есть undefined, возможно, вы отключили отчет об ошибках? Извлеките ключ из функции шифрования, чтобы подтвердить это.

Другая проблема - ошибка в JS-библиотеке Mcrypt. Эта библиотека заполняет ключ шифрования \0, если длина ключа меньше 32 байт, проблема в том, что этот не, как функция PHP mcrypt_encrypt заполняет ключ. Функция mcrypt_encrypt заполняет ключ до ближайшей допустимой длины ключа (16, 24 или 32 байта). Проблема в mcrypt.js находится в строках 63 и 64, измените это:

if(key.length<32)
    key+=Array(33-key.length).join(String.fromCharCode(0));

:

if(key.length<16)
    key+=Array(17-key.length).join(String.fromCharCode(0));
else if(key.length<24 && key.length>16)
    key+=Array(25-key.length).join(String.fromCharCode(0));
else if(key.length<32 && key.length>24)
    key+=Array(33-key.length).join(String.fromCharCode(0));

Теперь мы можем подтвердить исправление...

PHP:

function string_encrypt($string) {
    $crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, "", $string, MCRYPT_MODE_ECB);
    return $crypted_text;
}

$test_str = "This is test message to be encrypted.";
$enc_str = string_encrypt($test_str);
echo bin2hex($enc_str);

Output:
f98fca4ddc4c10d6cd47df56b081b78566ee4facbcf2254b46f7809d9b255529d2078f28b150e802d72818be1888536fac6219f6ce7b9d9332a24afa09288f0e

JavaScript:

function toHex(str) {
    var hex = '';
    for(var i=0;i<str.length;i++) {
        var val = ''+str.charCodeAt(i).toString(16);
        if(val.length == 1)
            hex += '0'+val;
        else
            hex += val;
    }
    return hex;
}

var enc_str = mcrypt.Encrypt("This is test message to be encrypted.", "", "", "rijndael-256", "ecb");
alert(toHex(enc_str));

Output:
f98fca4ddc4c10d6cd47df56b081b78566ee4facbcf2254b46f7809d9b255529d2078f28b150e802d72818be1888536fac6219f6ce7b9d9332a24afa09288f0e

Наконец, все эти функции шифрования производят двоичный файл как свой вывод. Двоичные файлы не могут быть написаны как обычный текст в большинстве случаев, не повреждая данные. Чтобы решить эту проблему, либо закодируйте двоичный код на Hex, либо Base64, а затем декодируйте его перед попыткой расшифровки.

Итак, чтобы все работало...

<?php 
$key = 'testtesttesttesttesttesttesttest';

function string_encrypt($string, $key) {
    $crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_ECB);
    return $crypted_text;
}

function string_decrypt($encrypted_string, $key) {
    $decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted_string, MCRYPT_MODE_ECB);
    return trim($decrypted_text);
}

echo $test_str = 'This is test message to be encrypted.';   echo '<br />';
$enc_str = string_encrypt($test_str, $key);
echo bin2hex($enc_str);                                     echo '<br />';
echo string_decrypt($enc_str, $key);                        echo '<br />';

?>

<script src='rijndael.js'></script>
<script src='mcrypt.js'></script>

<script lang='javascript'>
    function toHex(str) {
        var hex = '';
        for(var i=0;i<str.length;i++) {
            var val = ''+str.charCodeAt(i).toString(16);
            if(val.length == 1)
                hex += '0'+val;
            else
                hex += val;
        }
        return hex;
    }
    function hexToString (hex) {
        var str = '';
        for (var i=0; i<hex.length; i+=2) {
            str += ''+String.fromCharCode(parseInt(hex.charAt(i)+hex.charAt(i+1), 16));
        }
        return str;
    }
    var enc_str = mcrypt.Encrypt('<?php echo $test_str ?>', '', 'testtesttesttesttesttesttesttest', 'rijndael-256', 'ecb');
    alert(toHex(enc_str));
    alert(mcrypt.Decrypt(hexToString('<?php echo bin2Hex($enc_str) ?>'), '', 'testtesttesttesttesttesttesttest', 'rijndael-256', 'ecb').replace(/\x00+$/g, '')); 
</script>

Еще несколько заметок...

  • Вы не можете trim выводить функцию string_encrypt. Это приведет к удалению ведущих или завершающих нулей, которые сделают так, что вы не сможете расшифровать вывод.
  • Режим ECB небезопасен, и вы действительно не должны его использовать. CBC - это путь. CBC требует IV, а IV должен быть одинаковым для шифрования и дешифрования.
  • Шифрование Javascript не безопасно по разным причинам, учитывая ваше использование. Любой может просто просмотреть источник страниц или отладить запущенный javascript, чтобы получить ключ шифрования. Прочтите ссылку, размещенную ntoskrnl в комментариях к вашему вопросу.

Update:

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

Что касается конечных символов при расшифровке с помощью javascript, вам необходимо обрезать дешифрованный вывод. Вы делаете это в своем методе PHP string_decrypt, но не в своем javascript. Вы можете обрезать дешифрованный вывод, выполнив замену регулярного выражения на всех символах \0 в конце строки.

Пример:

mcrypt.Decrypt(dec_str,'').replace(/\x00+$/g, '')

Я должен был включить это в свой первоначальный пост, но я не заметил символов \0 в выходе, потому что поле предупреждения FF не отображает их. Извините.

Наконец, я заметил еще одну ошибку в JS-библиотеке Mcrypt. Строки с 41 по 47:

var ciphers={       //  block size, key size
    "rijndael-128"  :[  16,         32],
    "rijndael-192"  :[  24,         32],
    "rijndael-256"  :[  32,         32],
    "serpent"       :[  16,         32],
    "twofish"       :[  16,         32],
}

Обратите внимание на запятую в конце строки "twofish". Firefox и Chrome, похоже, не возражают против этого, но IE8 сообщит об ошибке и не сможет загрузить библиотеку mcrypt из-за этого. Чтобы исправить проблему, выполните следующие действия:

"twofish"       :[  16,         32],

в

"twofish"       :[  16,         32]
+7
источник

Что я сделал:

<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<?php 
$key = '12345678911234567892123456789312';

function string_encrypt($string, $key) {
    $crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_ECB);
    return base64_encode($crypted_text);
}

function string_decrypt($encrypted_string, $key) {
    return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($encrypted_string), MCRYPT_MODE_ECB);
}

echo 'Provided Text:    <br />' . $test_str =  'this is test काठमाडौं - राष्ट्रिय सुरक्षा परिषद्ले आसन्न संविधानसभा चुनावको सुरक्षामा नेपाली सेना खटाउने निर्णय गरेको छ। मंगलबार साँझ बसेको परिषद् बैठकले सुरक्षा अवस्था संवेदनशील भएको कारण देखाउँदै सात वर्षपछि सेना परिचालनका लागि मन्त्रिपरिषदसमक्ष सिफारिस गर्ने निर्णय गरेको हो। this is test';                           
echo '<br />';echo '<br />';

echo 'Encrypted Value:  <br />' . $enc_str = string_encrypt($test_str, $key);
echo '<br />';echo '<br />';

echo 'Decrypted Value:  <br />' . string_decrypt($enc_str, $key);
echo '<br />';echo '<br />';
?>
<script src='stringcoders.base64.js'></script>
<script src='rijndael.js'></script>
<script src='mcrypt.js'></script>

<script lang='javascript'  charset="utf-8">
    var is_IE = /*@[email protected]*/false;
    var message = '';

    var str = '<?php echo $test_str ?>';
    (is_IE) ? (message+= 'Provided Text:' + str) : console.log('Provided Text: \n' + str);
    str = unescape(encodeURIComponent(str));

    /* 
        I added this. Converted to ISO Latin before encryting and vice versa on decryption.
        Though don't know how this made work.
    */  
    var enc_str = mcrypt.Encrypt(str, '');
    enc_str = base64.encode(enc_str);
    (is_IE) ? (message+= 'Encrypted Value:' + enc_str) : console.log('\nEncyrpted Value:\n' + enc_str);

    var dec_str = base64.decode(enc_str);
    dec_str = mcrypt.Decrypt(dec_str, '').replace(/\x00+$/g, '');
    dec_str = decodeURIComponent(escape(dec_str));
    (is_IE) ? (message+= 'Decrypted Value:' + dec_str) : console.log('\nDecrypted Value:\n' + dec_str); 

    (is_IE) ? alert(message) : '';
</script>
+1
источник

Связанные вопросы


Похожие вопросы

Посмотрите другие вопросы по меткам или Задайте вопрос