AES 256 на стороне клиента (JS) и на сервере (PHP)

4

Я пытаюсь зашифровать и дешифровать данные на стороне сервера и клиента, используя тот же тип операции, который является AES-256.

На сервере я использую PHP и клиент, я использую CryptoJS до сих пор, я мог только зашифровать и расшифровать клиент на сервере, см. код:

JS

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/pbkdf2.js"></script>
<script>
    var salt = CryptoJS.lib.WordArray.random(128/8); 
    var key256Bits500Iterations = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 256/32, iterations: 500 });
    var iv  = CryptoJS.enc.Hex.parse('101112131415161718191a1b1c1d1e1f');

    var encrypted = CryptoJS.AES.encrypt("Message", key256Bits500Iterations, { iv: iv });  
    var data_base64 = encrypted.ciphertext.toString(CryptoJS.enc.Base64); 
    var iv_base64   = encrypted.iv.toString(CryptoJS.enc.Base64);       
    var key_base64  = encrypted.key.toString(CryptoJS.enc.Base64);
</script>

PHP

<?php
    $encrypted = base64_decode("data_base64"); // data_base64 from JS
    $iv        = base64_decode("iv_base64");   // iv_base64 from JS
    $key       = base64_decode("key_base64");  // key_base64 from JS

    $plaintext = rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv ), "\t\0 " );

Как я могу шифровать и расшифровывать данные с обеих сторон (клиент и сервер), чтобы общаться на одном языке с помощью PHP и CryptoJS?

  • 0
    Ключи должны быть длиной 16, 24 или 32 байта, а IV должны быть длиной 16 байтов. Они?
  • 0
    @ArtjomB. Исправьте эту ошибку, но теперь она приводит к множеству странных символов (сбой), которые могут быть ...?
Показать ещё 3 комментария
Теги:
encryption
cryptography
cryptojs

1 ответ

2
Лучший ответ

Ваш код выглядит отлично, кроме несоответствия заполнения. CryptoJS по умолчанию использует PKCS # 5/PKCS # 7, тогда как MCrypt поддерживает только ZeroPadding.

Если вы отправляете текстовые текстовые тексты, вы можете безопасно использовать

CryptoJS.AES.encrypt("Message", key, { iv: iv, padding: CryptoJS.pad.ZeroPadding });

Если нет, тогда вы должны использовать правильный pkcs7unpad в PHP:

$plaintext = pkcs7unpad( mcrypt_decrypt( MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv ), 16 );

Другие проблемы с вашим кодом заключаются в том, что вы напрямую используете CryptoJS.AES.encrypt(...).toString(). Это создаст строку в формате OpenSSL, которая не является чисто зашифрованным текстом. Вы должны использовать

CryptoJS.AES.encrypt(...).ciphertext.toString(CryptoJS.enc.Base64);

чтобы быть уверенным в кодировке.


Прямо сейчас, это только обфускация, так как вы отправляете ключ вместе с зашифрованным текстом. Я подозреваю, что вы хотите получить ключ в PHP тоже. Если да, то вам нужно будет только отправить случайную соль вместе с зашифрованным текстом в предположении, что сервер знает пароль.

PHP предоставляет реализацию PBKDF2 с версии 5.5 и далее.


Полная часть JavaScript без участия PBKDF2:

var message = 'My string - Could also be an JS array/object';
var iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
var key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8'; // 256-bit hex encoded

var keyBytes = CryptoJS.enc.Hex.parse(key);
var ivBytes = CryptoJS.enc.Hex.parse(iv);

var encrypt = CryptoJS.AES.encrypt(message, keyBytes, {
    iv: ivBytes, 
    padding: CryptoJS.pad.ZeroPadding 
}).ciphertext.toString(CryptoJS.enc.Base64);

дает:

j86KHBVRsDGKUnOiYdkEotsFL/LY/1tzz/h3Ay + vlEX11fC055m7vaF6q7w13eUj

Полная часть PHP без участия PBKDF2:

<?php

$iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
$key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8';
$ct = 'j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj';

$ivBytes = hex2bin($iv);
$keyBytes = hex2bin($key);
$ctBytes = base64_decode($ct);

$decrypt = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $keyBytes, $ctBytes, MCRYPT_MODE_CBC, $ivBytes));

echo $decrypt;

дает:

Моя строка - также может быть JS-массив/объект

То же самое можно сделать с расширением OpenSSL:

<?php
$iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
$key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8';
$ct = 'j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj';

$ivBytes = hex2bin($iv);
$keyBytes = hex2bin($key);
$ctBytes = base64_decode($ct);

$decrypt = openssl_decrypt($ctBytes, "aes-256-cbc", $keyBytes, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $ivBytes);
echo($decrypt);
  • 0
    Большой !! Спасибо !!! может развиваться с вашей помощью, я очень рад = DDD. Я просто оставил сомнение, которое связано с вопросом контекста: как все еще расшифровывать в JS? Я попробовал этот код, но все равно не буду .. var decrypt = CryptoJS.AES.encrypt(encrypt, keyBytes, { iv: ivBytes});
  • 0
    В этом случае вам нужно создать объект CipherParams и передать его функции дешифрования: var decrypt = CryptoJS.AES.decrypt(CryptoJS.lib.CipherParams({ciphertext: CryptoJS.enc.Base64.parse(encrypt)}), keyBytes, { iv: ivBytes}); , См. Code.google.com/p/crypto-js/#The_Cipher_Input.
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню