Воссоздание MCRYPT_RIJNDAEL_128 в node.js

Попытка воссоздать следующий код шифрования php в node.js:

$size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($size, MCRYPT_RAND);
$msg = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, 'MY_KEY_LONG_STRING', 'PLAINTEXT', MCRYPT_MODE_ECB, $iv));

Пробовал это:

var text = 'PLAINTEXT';
var len = text.length;
for (var i = 0; i < 16 - len % 16; i++) {  // pad to multiple of block size 
    text += '\0';
}
var key = 'MY_KEY_LONG_STRING';
key = key.substr(0, 16); // trim to expected key size for aes128

var cipher = crypto.createCipher('aes-128-ecb', key);
cipher.setAutoPadding(false); // did our own padding, to match mcrypt_encrypt
var encrypted = cipher.update(text, 'utf8', 'base64');
encrypted += cipher.final('base64');

Получение другого результата от php one...

Также попытался создать шифр с IV (который даже не должен использоваться в aes-128-ecb):

var cipher = crypto.createCipheriv('aes-128-ecb', key, '');

Также отличается результат от php. Любые идеи, как заставить это вести себя так же, как версия PHP?

2 ответа

Решение

Играть две довольно плохо сконструированные библиотеки друг против друга может быть весело. Вместо того, чтобы делать всю работу, я помогу вам вместе с идеями в соответствии с просьбой:

  • вместо удаления ключевых байтов PHP расширяет их, используя заполнение нулями до следующего доступного размера ключа - в вашей ситуации это будет 192 бита или 24 байта; для этого нужно указать aes-192-ecb как алгоритм (вы должны продолжать использовать MCRYPT_RIJNDAEL_128 но подставим, что 128 в PHP - это размер блока, а не размер ключа)
  • заполнение некорректно, PHP заполняет 0..15 нулевых байтов вместо 1..16 байтов
  • Вы не можете использовать аргумент 2 createCipher вторым аргументом является пароль; node.js выполняет вывод ключа, если вы его используете, поэтому вам нужно использовать три аргумента createCipher вместо этого и поставьте любые 16 байтов IV

Код IV в PHP только облагается налогом генератор случайных чисел, IV не используется.


Код для заполнения

var padSize = 16 - ((len + 16 - 1) % 16 + 1);
for (var i = 0; i < padSize; i++) {  // pad 0 .. 15 until to multiple of block size 
    text += '\0';
}

Или вы можете использовать свой собственный метод заполнения, если len % 16 == 0,

Вот мой код для решения проблемы с переходом с PHP на NodeJS. У меня строгий ключ 32 байта, поэтому я должен использовать aes-256-ecb,

PHP-код, который я хочу переписать:

$text = "Some super mega text I want to encode";
$skey = "rcbTw667C7zxghZ5U3gwhQlp22t8c5Rq";

function encode($text,$skey) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $skey, $text, MCRYPT_MODE_ECB, $iv);
    return base64_encode($crypttext);
}

echo encode($text,$skey);

Выход:

dU1eOy+YwkYvm/KCTB8aqR1UsisyrHrvBu+E/H3G/s0aagMDKlNFekGXNQyFMFJD

NodeJS:

var crypto = require('crypto');

var text = "Some super mega text I want encode";
var skey = "rcbTw667C7zxghZ5U3gwhQlp22t8c5Rq";

function encode(text, skey) {
    var len = text.length;
    var padSize = 16 - ((len + 16 - 1) % 16 + 1);
    for (var i = 0; i < padSize; i++) { 
        text += '\0';
    }
    var cipher = crypto.createCipheriv('aes-256-ecb', skey, '');
    cipher.setAutoPadding(false);
    var encrypted = cipher.update(text, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
}

console.log(encode(text, skey));

Выход:

dU1eOy+YwkYvm/KCTB8aqR1UsisyrHrvBu+E/H3G/s0aagMDKlNFekGXNQyFMFJD

Также работает пакет NodeJS mcrypt:

npm install mcrypt

Код:

var text = "Some super mega text I want encode";
var skey = "rcbTw667C7zxghZ5U3gwhQlp22t8c5Rq";

function encode(text, skey) {
    var MCrypt = require('mcrypt').MCrypt;
    var rijEcb = new MCrypt('rijndael-128', 'ecb');
    rijEcb.open(skey);
    var ciphertext = rijEcb.encrypt(text);
    return ciphertext.toString('base64');
}

console.log(encode(text, skey));

Выход:

dU1eOy+YwkYvm/KCTB8aqR1UsisyrHrvBu+E/H3G/s0aagMDKlNFekGXNQyFMFJD

Я попробовал другой вариант, но ничего не получилось, но у меня это сработало.

function encrypt(text) {
  text = '' + text;
  var crypto = require('crypto');
  var len = text.length;
  var padSize = 16 - (((len + 16 - 1) % 16) + 1);
  var data = String.fromCharCode(padSize);
  var text = text + data.repeat(padSize);

  var cipher = crypto.createCipheriv('aes-128-ecb','secretKey', '');
  cipher.setAutoPadding(false);
  var encrypted = cipher.update(text, 'utf8', 'base64');
  encrypted += cipher.final('base64');
  return encrypted;
}

Similer в PHP

function aes128Encrypt($str,$key){
$block = mcrypt_get_block_size('rijndael_128', 'ecb');
$pad = $block - (strlen($str) % $block);
$str .= str_repeat(chr($pad), $pad);
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB));
}
Другие вопросы по тегам