Зашифровать с помощью 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>
Какой шаг я пропускаю?
6 ответов
Мне потребовалось то же самое, и я написал небольшую библиотеку, которая работает для 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) j.s = 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 (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
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 = random_bytes(16);
$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=
Скотт Аркишевский ВАЖНО: Поскольку мы не аутентифицируем наш зашифрованный текст, дешифрование становится уязвимым для атак оракула. Смотрите также: аутентифицированное шифрование в PHP.
На стороне CryptoJS:
Ваш ключ - всего 13 печатных символов ASCII, что очень слабо. Макрипт добавил ключ к правильному размеру ключа, используя нулевые байты.
Преобразуйте ключ и 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='
/**
* Scott Arciszewski DANGER DANGER WILL ROBINSON!
*
* This example code doesn't demonstrate AUTHENTICATED ENCRYPTION
* and is therefore vulnerable to chosen-ciphertext attacks.
*
* NEVER USE THIS CODE TO PROTECT SENSITIVE DATA!
*/
// 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))
Не зацикливайтесь на кодировании, просто используйте декодер base64
по php-коду:
$encrypt_val=base64_encode("value");
а на js просто:
var my_orignal_val = window.atob(passed_val);
Этого будет достаточно для вашего требования.
Вы используете две библиотеки, которые пытаются разместить ввод, который, строго говоря, недопустим. 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-байтовые блоки). Поскольку такие данные должны быть дополнены. Макрипт делает это неинъективным способом, просто добавляя нули. Если вы кодируете только строки, это не станет для вас большой проблемой, так как строки в кодировке utf8 никогда не содержат нулевых байтов, так что вы можете просто удалить их ( CryptoJS даже поддерживает это изначально).
Самое простое решение всех этих проблем - избегать самостоятельной реализации какой-либо криптографии (в любом случае, это настоятельно не рекомендуется без широкого знания предмета). Можете ли вы вместо этого передать свою конфиденциальную информацию через https, который будет использовать TLS (ранее называемый SSL) для шифрования и аутентификации канала?
Это решение для тех, кто не может установить формат JSON наcryptojs.aes.decrypt
функция:
function encryptCryptoJsStyle($value, $passphrase)
{
$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);
// Base64 encode the final result
return base64_encode('Salted__' . $salt . $encrypted_data);
}
Шифрование Javascript
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js" integrity="sha512-E8QSvWZ0eCLGk4km3hxSsNmGWbLtSCSUcewDQPQWZF6pEU8GlT8a5fF32wOl1i8ftdMhssTrF/OhyGWwonTcXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function encrypt(str) {
var encoded = "";
for (i=0; i<str.length;i++) {
var a = str.charCodeAt(i);
var b = a ^ 51; // bitwise XOR with any number, e.g. 123
encoded = encoded+String.fromCharCode(b);
}
return btoa(encoded);
}
Расшифровка PHP
function decrypt($encoded) {
$encoded =base64_decode($encoded);
$decoded = "";
for( $i = 0; $i < strlen($encoded); $i++ ) {
$b = ord($encoded[$i]);
$a = $b ^ 51; // <-- must be same number used to encode the character
$decoded .= chr($a);
}
return $decoded;
}
КЛЮЧ -PHP Расшифровать
function decrypt($passphrase, $enc_text)
{
$enc_text = json_decode($enc_text, true);
try {
$slam_ol = hex2bin($enc_text["slam_ltol"]);
$iavmol = hex2bin($enc_text["iavmol"]);
} catch (Exception $e) {
return null;
}
$ciphertext = base64_decode($enc_text["amtext"]);
$iterations = 999;
$key = hash_pbkdf2("sha512", $passphrase, $slam_ol, $iterations, 64);
$decrypted = openssl_decrypt($ciphertext, 'aes-256-cbc', hex2bin($key), OPENSSL_RAW_DATA, $iavmol);
return $decrypted;
}
КЛЮЧ -шифрование javascript
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js" integrity="sha512-E8QSvWZ0eCLGk4km3hxSsNmGWbLtSCSUcewDQPQWZF6pEU8GlT8a5fF32wOl1i8ftdMhssTrF/OhyGWwonTcXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function encrypt(passphrase, plain_text) {
var slam_ol = CryptoJS.lib.WordArray.random(256);
var iv = CryptoJS.lib.WordArray.random(16);
var key = CryptoJS.PBKDF2(passphrase, slam_ol, {
hasher: CryptoJS.algo.SHA512,
keySize: 64 / 8,
iterations: 999
});
var encrypted = CryptoJS.AES.encrypt(plain_text, key, {
iv: iv
});
var data = {
amtext: CryptoJS.enc.Base64.stringify(encrypted.ciphertext),
slam_ltol: CryptoJS.enc.Hex.stringify(slam_ol),
iavmol: CryptoJS.enc.Hex.stringify(iv)
}
return JSON.stringify(data);
}