Node.js `crypto.final` заставляет зашифрованный результат отличаться от PHP` mcrypt_encrypt`

Сначала шифрование Node.js.

// Both of key and IV are hex-string, but I hide them in Stackoverflow. var secretKey = new Buffer('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), // 48 chars iv = new Buffer('bbbbbbbbbbbbbbbb', 'hex'); // 16 chars var str = 'This string will be encrypted.'; var cipher = crypto.createCipheriv('des-ede3-cbc', secretKey, iv), cryptedStr = cipher.update(str, 'utf8', 'base64') + cipher.final('base64'); 

Затем PHP mcrypt.

 $key = pack('H*', "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); $iv = pack('H*', "bbbbbbbbbbbbbbbb"); $string = 'This string will be encrypted.'; $text = mcrypt_encrypt(MCRYPT_3DES, $key, $string, MCRYPT_MODE_CBC, $iv); $text_base64 = base64_encode($text); 

Проблема.

В той же строке, тот же алгоритм и одна и та же кодировка.

Еще есть небольшая часть, которая не соответствует cipher.final() .

Ниже приведен реальный объем выборки.

 // Node.js output. UKBI17EIHKNM2EU48ygsjil5r58Eo1csByAIFp9GhUw= ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Same part // PHP output. UKBI17EIHKNM2EU48ygsjil5r58Eo1csAY4C0JZoyco= ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Same part 

Почему cipher.final() делает результаты разными?

Как можно сделать те же результаты в Node.js при условии, что они не изменяют PHP-код .

Поскольку вы не можете изменить свой PHP-код, вам нужно будет изменить код node.js.

Проблема в том, что криптомодуль node.js использует только дополнение PKCS # 7, тогда как PHP использует только нулевое дополнение. Однако вы можете отключить дополнение в node.js ( setAutoPadding(false) ) для реализации собственного нулевого заполнения:

 function zeroPad(buf, blocksize){ if (typeof buf === "string") { buf = new Buffer(buf, "utf8"); } var pad = new Buffer((blocksize - (buf.length % blocksize)) % blocksize); pad.fill(0); return Buffer.concat([buf, pad]); } 

И используйте его вот так:

 var secretKey = new Buffer('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'hex'), // 48 chars iv = new Buffer('bbbbbbbbbbbbbbbb', 'hex'); // 16 chars var str = 'This string will be encrypted.'; var cipher = crypto.createCipheriv('des-ede3-cbc', secretKey, iv); cipher.setAutoPadding(false); var cryptedStr = cipher.update(zeroPad(str, 8), 'utf8', 'base64') + cipher.final('base64'); console.log(cryptedStr); 

Вывод:

 UKBI17EIHKNM2EU48ygsjil5r58Eo1csAY4C0JZoyco= 

Ниже приведена реализация сопоставимой функции:

 function zeroUnpad(buf, blocksize){ var lastIndex = buf.length; while(lastIndex >= 0 && lastIndex > buf.length - blocksize - 1) { lastIndex--; if (buf[lastIndex] != 0) { break; } } return buf.slice(0, lastIndex + 1).toString("utf8"); }