Шифрование с помощью PHP, расшифровка с помощью Javascript (cryptojs)

У меня проблемы с базовым шифрованием / расшифровкой. Я посмотрел на рабочий стол, но не нашел рабочего примера.

-Я буду шифровать в php, расшифровать cryptojs для небольшого уровня безопасности

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"> <? $text = "this is the text here"; $key = "encryptionkey"; $msgEncrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)); $msgBase64 = trim(base64_encode($msgEncrypted)); echo "<h2>PHP</h2>"; echo "<p>Encrypted:</p>"; echo $msgEncrypted; echo "<p>Base64:</p>"; echo $msgBase64; ?> <p>AES Decrypt</p> <script> var key = 'encryptionkey'; var encrypted = "<?php echo $msgBase64 ?>"; //tried var base64decode = CryptoJS.enc.Base64.parse(encrypted); var decrypted = CryptoJS.AES.decrypt(encrypted, key); console.log( decrypted.toString(CryptoJS.enc.Utf8) ); </script> 

На каком этапе я пропущу?

Мне нужно то же самое, и я написал небольшую библиотеку, которая работает для CryptoJS 3.x и PHP с поддержкой openssl. Надеюсь, что это поможет, исходный плюс примеры файлов здесь https://github.com/brainfoolong/cryptojs-aes-php

PHP Lib

 /** * Decrypt data from a CryptoJS json encoding string * * @param mixed $passphrase * @param mixed $jsonString * @return mixed */ function cryptoJsAesDecrypt($passphrase, $jsonString){ $jsondata = json_decode($jsonString, true); $salt = hex2bin($jsondata["s"]); $ct = base64_decode($jsondata["ct"]); $iv = hex2bin($jsondata["iv"]); $concatedPassphrase = $passphrase.$salt; $md5 = array(); $md5[0] = md5($concatedPassphrase, true); $result = $md5[0]; for ($i = 1; $i < 3; $i++) { $md5[$i] = md5($md5[$i - 1].$concatedPassphrase, true); $result .= $md5[$i]; } $key = substr($result, 0, 32); $data = openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv); return json_decode($data, true); } /** * Encrypt value to a cryptojs compatiable json encoding string * * @param mixed $passphrase * @param mixed $value * @return string */ function cryptoJsAesEncrypt($passphrase, $value){ $salt = openssl_random_pseudo_bytes(8); $salted = ''; $dx = ''; while (strlen($salted) < 48) { $dx = md5($dx.$passphrase.$salt, true); $salted .= $dx; } $key = substr($salted, 0, 32); $iv = substr($salted, 32,16); $encrypted_data = openssl_encrypt(json_encode($value), 'aes-256-cbc', $key, true, $iv); $data = array("ct" => base64_encode($encrypted_data), "iv" => bin2hex($iv), "s" => bin2hex($salt)); return json_encode($data); } 

Javascript Lib

 var CryptoJSAesJson = { stringify: function (cipherParams) { var j = {ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)}; if (cipherParams.iv) j.iv = cipherParams.iv.toString(); if (cipherParams.salt) js = cipherParams.salt.toString(); return JSON.stringify(j); }, parse: function (jsonStr) { var j = JSON.parse(jsonStr); var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)}); if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv) if (js) cipherParams.salt = CryptoJS.enc.Hex.parse(js) return cipherParams; } } 

Пример Javascript

 var encrypted = CryptoJS.AES.encrypt(JSON.stringify("value to encrypt"), "my passphrase", {format: CryptoJSAesJson}).toString(); var decrypted = JSON.parse(CryptoJS.AES.decrypt(encrypted, "my passphrase", {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8)); 

Пример PHP

 $encrypted = cryptoJsAesEncrypt("my passphrase", "value to encrypt"); $decrypted = cryptoJsAesDecrypt("my passphrase", $encrypted); 

Вот рабочий пример шифрования вашей строки с помощью PHP и дешифрования ее с помощью CryptoJS.

На стороне PHP:

Используйте MCRYPT_RIJNDAEL_128 (не 256) для сопряжения с AES. Здесь 128 – это блокировка, а не ключ.

Отправьте IV , тоже. Вам нужно IV расшифровать.

 $text = "this is the text here"; $key = "encryptionkey"; // Note: MCRYPT_RIJNDAEL_128 is compatible with AES (all key sizes) $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND); $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv); echo "iv:".base64_encode($iv)."\n"; echo "ciphertext:".base64_encode($ciphertext)."\n"; 

Вот пример вывода тестового прогона:

 iv:BMcOODpuQurUYGICmOqqbQ== ciphertext:ZJAab8YtkRq5TL7uyIR7frM2b3krftJzn1pTqRTAda4= 

На стороне CryptoJS:

Ваш ключ – всего 13 символов ASCII, которые очень слабы. Mcrypt наполнил ключ действительным ключом, используя байты ZERO .

Преобразуйте ключевые и IV в текстовые массивы .

У меня не было большого количества расшифровки удалений с помощью шифрованного текста в виде массива слов, поэтому я оставил его в формате Base64 .

 CryptoJS = require("crypto-js") // Mcrypt pads a short key with zero bytes key = CryptoJS.enc.Utf8.parse('encryptionkey\u0000\u0000\u0000') iv = CryptoJS.enc.Base64.parse('BMcOODpuQurUYGICmOqqbQ==') // Keep the ciphertext in Base64 form ciphertext = 'ZJAab8YtkRq5TL7uyIR7frM2b3krftJzn1pTqRTAda4=' // Mcrypt uses ZERO padding plaintext = CryptoJS.AES.decrypt(ciphertext, key, { iv: iv, padding: CryptoJS.pad.ZeroPadding }) // I ran this in nodejs process.stdout.write(CryptoJS.enc.Utf8.stringify(plaintext)) 

Вы используете две библиотеки, которые пытаются разместить вход, который, строго говоря, недействителен. Для Rijndael требуются ключи, которые имеют случайные байтовые строки длиной 16, 24 или 32 байта. Вы предоставляете 13-значную строку. Mcrypt, библиотека PHP, использует строку (предположительно закодированную utf8) непосредственно как двоичный вход и нуль заполняет ее до требуемых 32 байтов для MCRYPT_RIJNDAEL_256 . CryptoJS, с другой стороны, решает, что вы ввели что-то вроде кодовой фразы и вместо этого используете функцию деривации ключа для генерации 32-байтового ключа .

Кроме того, используемые алгоритмы шифрования даже не совпадают. Mcrypt использует редко реализованный вариант оригинального Rijndael для 256-битной версии, тогда как CryptoJS реализует широко известный вариант AES256 предложения Rijndael. 128-разрядная версия обоих ( MCRYPT_RIJNDAEL_128 и AES128) идентична.

Третья проблема, с которой вам предстоит столкнуться, заключается в том, что Mcrypt также использует сумасшедшую схему дополнений для зашифрованных данных. Поскольку Rijndael является блочным шифрованием, он может шифровать только блоки из 16, 24 или 32 байта (в зависимости от варианта – AES всегда использует 16 байтовых блоков). Поскольку такие данные должны быть дополнены. Mcrypt делает это неинъекционным способом, просто добавляя нули. Если вы только кодирующие строки, это не будет для вас большой проблемой, так как строки, закодированные в utf8, никогда не содержат нулевых байтов, поэтому вы можете просто отключить их ( CryptoJS поддерживает даже это ).

Самое простое исправить все эти проблемы – это избежать необходимости выполнять какую-либо криптографию самостоятельно (в любом случае она сильно не приветствуется без широкого знания предмета). Можете ли вы вместо этого передать свою конфиденциальную информацию через https, которая будет использовать TLS (ранее называемый SSL) для шифрования и аутентификации канала?