Intereting Posts
Как отправить значения массива флажков через Ajax с помощью jQuery? Phalanger не может найти мои php-классы Самый простой способ для ссылки на проверку электронной почты PHP Автозаполнение текстового поля с помощью DOJO file_exists () возвращает false, даже если файл существует (удаленный URL) Удалить папку и все файлы по FTP-соединению Как проверить, где Apache ищет файл php.ini? PHP проверяет, является ли входящий запрос JSON-типом PHP ini file_get_contents внешний url typehinting: метод должен принимать любой $ arg, являющийся объектом Лучшие практики в PHP и MySQL с международными строками Загрузка видео на Youtube с использованием API данных Youtube V3 и клиента API Google PHP – получение сообщения 401 (несанкционированное) MODx :: Получить идентификатор сеанса, установленный MODx для использования в модуле как запустить php-скрипт из командного файла jqplot этикетка с надписью / легенда цвета и линии

Выполните шифрование с помощью PHP (openssl_encrypt), затем расшифруйте с помощью JS (CryptoJS)

Мой первый раз использовал CryptoJS, и я изо всех сил пытаюсь расшифровать строку, которую я зашифровал с помощью openssl_encrypt () в PHP.

PHP 5.6.13.0 и CryptoJS 3.1.2


Во-первых, мой PHP:

$encryptHash = hash_pbkdf2("sha256", "0000", "secret", 1000, 32); var_dump($encryptHash); $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc')); var_dump(bin2hex($iv)); $encrypted = openssl_encrypt("hello! this is my string!", 'aes-256-cbc', $encryptHash, 0, $iv); var_dump($encrypted); $encrypted = base64_encode($encrypted.":".bin2hex($iv)); echo "\r\n".$encrypted; 

Это дает мне следующий результат:

 string(32) "59b6ab46d379b89d794c87b74a511fbd" string(32) "0aaff094b6dc29742cc98a4bac8bc8f9" string(44) "xHIxg1HDUOqyhBmAaU2Sx3ct8GaKaeE5w4d1KM1yuDw=" eEhJeGcxSERVT3F5aEJtQWFVMlN4M2N0OEdhS2FlRTV3NGQxS00xeXVEdz06MGFhZmYwOTRiNmRjMjk3NDJjYzk4YTRiYWM4YmM4Zjk= 

Теперь мой JS:

 var encryptedString = "eEhJeGcxSERVT3F5aEJtQWFVMlN4M2N0OEdhS2FlRTV3NGQxS00xeXVEdz06MGFhZmYwOTRiNmRjMjk3NDJjYzk4YTRiYWM4YmM4Zjk="; var key256Bits = CryptoJS.PBKDF2("0000", "secret", { keySize: 128/32, iterations: 1000, hasher: CryptoJS.algo.SHA256 }); var keyAsHex = key256Bits.toString(CryptoJS.enc.Hex); /* keyAsHex = "59b6ab46d379b89d794c87b74a511fbd" */ var rawData = atob(encryptedString); var rawPieces = rawData.split(":"); var crypttext = rawPieces[0]; var iv = rawPieces[1]; /* crypttext = "xHIxg1HDUOqyhBmAaU2Sx3ct8GaKaeE5w4d1KM1yuDw=" */ /* iv = "0aaff094b6dc29742cc98a4bac8bc8f9" */ /* So far so good? */ var plaintextArray = CryptoJS.AES.decrypt( { ciphertext: CryptoJS.enc.Base64.parse(crypttext) }, CryptoJS.enc.Hex.parse(keyAsHex), { iv: CryptoJS.enc.Hex.parse(iv) } ); /* plaintextArray: d.WordArray.n.extend.init sigBytes: -67 words: Array[8] 0: 1419734786 1: -2048883413 2: -1709437124 3: 736946566 4: 718053567 5: -64039355 6: 1868905697 7: -910423965 */ var output = CryptoJS.enc.Utf8.stringify(plaintextArray); /* output = "" */ 

Как вы можете видеть, мой вывод пустой строки. Кто-то пытался сделать что-то подобное? Я в тупике!

редактировать

Оказывается, мои ключевые длины были неправильными! Вот мой рабочий код (шифрование) и JS (расшифровка):


PHP:

 $encryptHash = hash_pbkdf2("sha256", "0000", "secret", 1000, 32, true); var_dump($encryptHash); $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc")); var_dump($iv); $encrypted = openssl_encrypt("hello! this is a test!", "aes-256-cbc", $encryptHash, 0, $iv); var_dump($encrypted); $encrypted = base64_encode($encrypted.":".bin2hex($iv)); echo "\r\n".$encrypted; 

Дает мне следующее:

 string(32) "Y½FËy©ØyLçÀJQ▼¢▄▄êI╩öo§(NtÙת‼ç" string(16) "àX§ $VÇ‼♣┘█²áÓßt" string(44) "VIzzao8Wdo8HPM015v6c5Q77ervGUIVbL6ERKRXb0fU=" Vkl6emFvOFdkbzhIUE0wMTV2NmM1UTc3ZXJ2R1VJVmJMNkVSS1JYYjBmVT06ODU1ODE1MjAyNDU2ODAxMzA1ZDlkYmZkYTBlMGUxNzQ= 

JS:

 var encryptedString = "Vkl6emFvOFdkbzhIUE0wMTV2NmM1UTc3ZXJ2R1VJVmJMNkVSS1JYYjBmVT06ODU1ODE1MjAyNDU2ODAxMzA1ZDlkYmZkYTBlMGUxNzQ="; var key256Bits = CryptoJS.PBKDF2("0000", "secret", { keySize: 256/32, iterations: 1000, hasher: CryptoJS.algo.SHA256 }); var rawData = atob(encryptedString); var rawPieces = rawData.split(":"); var crypttext = rawPieces[0]; var iv = CryptoJS.enc.Hex.parse(rawPieces[1]); var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(crypttext)}); var plaintextArray = CryptoJS.AES.decrypt( cipherParams, key256Bits, { iv: iv } ); var output = CryptoJS.enc.Utf8.stringify(plaintextArray); /* output === 'hello! this is a test!' */ 

TL; DR – попробуйте использовать 32-байтовый ключ, а не 16-байтовый ключ.

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

При попытке воспроизвести вашу проблему я не смог бы получить первый блок зашифрованного текста одинаковым при создании с помощью openssl_encrypt vs CryptoJS . Затем я удвоил длину ключа, и он сработал.

Ключ, который вы генерируете выше, составляет 32 символа, но только 16 байт после преобразования, поэтому попробуйте удвоить это и посмотреть, что произойдет.

FWIW, вот код PHP, который я использовал для проверки длины ключа:

 $data = "hello! this is a test!"; $method = 'aes-256-cbc'; $key = '59b6ab46d379b89d794c87b74a511fbd59b6ab46d379b89d794c87b74a511fbd'; $iv = '0aaff094b6dc29742cc98a4bac8bc8f9'; $e = openssl_encrypt( $data, $method, hex2bin( $key ), 0, hex2bin( $iv )); echo 'Ciphertext: [', bin2hex( base64_decode( $e )), "]\n"; echo 'Key: [', $key, "]\n"; echo 'Cleartext: [', openssl_decrypt( $e, $method, hex2bin( $key ), 0, hex2bin( $iv )), "]\n"; // Test with openssl on the command line as well, just to be sure! file_put_contents( 'clear.txt', $data ); $exec = "openssl enc -$method -e -in clear.txt -out encrypted.txt -base64 -nosalt -K $key -iv $iv"; exec ($exec); $out = file_get_contents( 'encrypted.txt' ); echo 'Ciphertext: [', bin2hex( base64_decode(trim($out))), "]\n"; 

И вот совместимый JavaScript, который я запускаю с помощью jsc на своем Mac:

 var data = "hello! this is a test!"; var key = '59b6ab46d379b89d794c87b74a511fbd59b6ab46d379b89d794c87b74a511fbd'; var iv = '0aaff094b6dc29742cc98a4bac8bc8f9'; var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(data), CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Hex.parse(iv) }); print( 'Ciphertext: [' + encrypted.ciphertext + ']' ); print( 'Key: [' + encrypted.key + ']' ); cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Hex.parse(encrypted.ciphertext.toString())}); var decrypted = CryptoJS.AES.decrypt(cipherParams, CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Hex.parse(iv) }); print( 'Cleartext: [' + decrypted.toString(CryptoJS.enc.Utf8) + ']'); 

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

ОБНОВИТЬ

Я только что обнаружил, что hash_pbkdf2() возвращает шестнадцатеричные строки ASCII по умолчанию, поэтому вам нужно либо преобразовать $encryptHash в двоичный файл с hex2bin() прежде чем передать его в openssl_encrypt() либо установить для последнего параметра hash_pbkdf2() значение true чтобы получить исходный вывод.

ОБНОВЛЕНИЕ 2

Я только что подтвердил, что ваш код будет работать, если вы внесете следующие изменения:

В PHP измените размер ключа от 32 до 64 байт и добавьте опцию raw output при генерации ключа:

 $encryptHash = hash_pbkdf2("sha256", "0000", "secret", 1000, 64, 1); 

Измените длину ключа от 128 до 256 бит в JavaScript:

 var key256Bits = CryptoJS.PBKDF2("0000", "secret", { keySize: 256/32, iterations: 1000, hasher: CryptoJS.algo.SHA256 }); 

Надеюсь, эти изменения будут работать, когда вы их попробуете.