Я нашел несколько вещей, которые могут быть причинами, по которым дешифрование / шифрование на PHP и Node.js не совпадают.
PHP использовал алгоритм MCRYPT_RIJNDAEL_256.AES 256 основан на MCRYPT_RIJNDAEL_256, но отличается от него.AES 256 это стандарт шифрования, но не алгоритм.
Если вы пытаетесь зашифровать что-то с помощью стандартных простых функций (например, «mcrypt_encrypt» и «mcrypt_decrypt» в PHP), вы не сможете увидеть всешаги, и вы, конечно, не можете знать, почему вы не можете расшифровать то, что вы зашифровали.Это может быть то же самое для Node.js, потому что нужно использовать функцию, которая может шифровать шаг за шагом, чтобы предотвратить подстановку к параметрам по умолчанию.
Чтобы зашифровать / расшифровать кое-что, что вам нужно знать (установить):
encryption method (algorythm)
encryption mode (CBF, ECB, CBC...)
key to decryption
key lenght
initialisation vector lenght
И проверьте это с обеих сторон.Это должно быть то же самое.Также нужно найти правильную комбинацию «метод шифрования» + «режим шифрования», которая наверняка работает с обеих сторон.
Мое решение - RIJNDAEL_256 + ECB .Вы должны установить node-rijndael , потому что он наверняка использует RIJNDAEL_256.Если нет - мой пример не будет работать.
Вот пример Node.js для шифрования .
Установите node-rijndael в какую-то папку, где должно быть два файла .js.
r256.js - это функции для шифрования / дешифрования.Я нашел это здесь .
var Rijndael = require('node-rijndael');
/**
* Pad the string with the character such that the string length is a multiple
* of the provided length.
*
* @param {string} string The input string.
* @param {string} chr The character to pad with.
* @param {number} length The base length to pad to.
* @return {string} The padded string.
*/
function rpad(string, chr, length) {
var extra = string.length % length;
if (extra === 0)
return string;
var pad_length = length - extra;
// doesn't need to be optimized because pad_length will never be large
while (--pad_length >= 0) {
string += chr;
}
return string;
}
/**
* Remove all characters specified by the chr parameter from the end of the
* string.
*
* @param {string} string The string to trim.
* @param {string} chr The character to trim from the end of the string.
* @return {string} The trimmed string.
*/
function rtrim(string, chr) {
for (var i = string.length - 1; i >= 0; i--)
if (string[i] !== chr)
return string.slice(0, i + 1);
return '';
}
/**
* Encrypt the given plaintext with the base64 encoded key and initialization
* vector.
*
* Null-pads the input plaintext. This means that if your input plaintext ends
* with null characters, they will be lost in encryption.
*
* @param {string} plaintext The plain text for encryption.
* @param {string} input_key Base64 encoded encryption key.
* @param {string} input_iv Base64 encoded initialization vector.
* @return {string} The base64 encoded cipher text.
*/
function encrypt(plaintext, input_key, input_iv) {
var rijndael = new Rijndael(input_key, {
mode: Rijndael.MCRYPT_MODE_ECB,
encoding: 'base64',
iv: input_iv
});
console.log("Rijndael.blockSize", Rijndael.blockSize);
var padded = rpad(plaintext, '\0', Rijndael.blockSize);
return rijndael.encrypt(padded, 'binary', 'base64');
}
/**
* Decrypt the given ciphertext with the base64 encoded key and initialization
* vector.
*
* Reverses any null-padding on the original plaintext.
*
* @param {string} ciphertext The base64 encoded ciphered text to decode.
* @param {string} input_key Base64 encoded encryption key.
* @param {string} input_iv Base64 encoded initialization vector.
* @param {string} The decrypted plain text.
*/
function decrypt(ciphertext, input_key, input_iv) {
var rijndael = new Rijndael(input_key, {
mode: Rijndael.MCRYPT_MODE_ECB,
encoding: 'base64',
iv: input_iv
});
console.log('lol', rijndael.decrypt(ciphertext, 'base64', 'binary'));
return rtrim(rijndael.decrypt(ciphertext, 'base64', 'binary'), '\0');
}
exports.decrypt = decrypt;
exports.encrypt = encrypt;
encrypt.js - это пример шифрования.
var crypto = require('crypto');
var key = new Buffer('theonetruesecretkeytorulethemall', 'utf-8').toString('base64'); //secret key to decrypt
var iv = crypto.randomBytes(32).toString('base64');
console.log({"key":key, "iv":iv});
var rijndael = require('./r256');
var plaintext = 'lalala'; //text to encrypt
var ciphertext = rijndael.encrypt(plaintext, key, iv);
console.log({"ciphertext":ciphertext});
ВотПример PHP для расшифровки .
<?php
echo "<PRE>";
$mcrypt_method = MCRYPT_RIJNDAEL_256;
$mcrypt_mode = MCRYPT_MODE_ECB;
$mcrypt_iv = '123456'; //needed only for encryption, but needed for mcrypt_generic_init, so for decryption doesn't matter what is IV, main reason it is IV can exist.
$mcrypt_key = 'theonetruesecretkeytorulethemall';
$data_to_decrypt = base64_decode('ztOS/MQgJyKJNFk073oyO8KklzNJxfEphu78ok6iRBU='); //node.js returns base64 encoded cipher text
$possible_methods = array_flip(mcrypt_list_algorithms());
if(empty($possible_methods[$mcrypt_method]))
{
echo "method $mcrypt_method is impossible".PHP_EOL;
exit();
}
$possible_modes = array_flip(mcrypt_list_modes());
if(empty($possible_modes[$mcrypt_mode]))
{
echo "mode $mcrypt_mode is impossible".PHP_EOL;
exit();
}
if(!@mcrypt_get_block_size($mcrypt_method, $mcrypt_mode))
{
echo "method $mcrypt_method does not support mode $mcrypt_mode".PHP_EOL;
exit();
}
$mcrypt = mcrypt_module_open($mcrypt_method,'', $mcrypt_mode, '');
$ivsize = mcrypt_enc_get_iv_size($mcrypt);
if($ivsize != strlen($mcrypt_iv))
{
$mcrypt_iv = str_pad($mcrypt_iv, $ivsize, '#');
}
if($ivsize < strlen($mcrypt_iv))
{
$mcrypt_iv=substr($mcrypt_iv,0,$ivsize);
}
$keysize = mcrypt_enc_get_key_size($mcrypt);
if($keysize != strlen($mcrypt_key))
{
$mcrypt_key = str_pad($mcrypt_key, $keysize, '#');
}
if($keysize < strlen($mcrypt_key))
{
$mcrypt_key=substr($mcrypt_key,0,$keysize);
}
$mcrypt_isblock = (int)mcrypt_enc_is_block_mode($mcrypt);
$mcrypt_blocksize = mcrypt_enc_get_block_size($mcrypt);
$mcrypt_method = mcrypt_enc_get_algorithms_name($mcrypt);
$mcrypt_mode = mcrypt_enc_get_modes_name($mcrypt);
echo "used method=$mcrypt_method \nmode=$mcrypt_mode \niv=$mcrypt_iv \nkey=$mcrypt_key \nkey with blocksize=$mcrypt_blocksize \nisblock=$mcrypt_isblock".PHP_EOL;
if(mcrypt_generic_init($mcrypt,$mcrypt_key,$mcrypt_iv)< 0)
{
echo "mcrypt_generic_init failed...".PHP_EOL;
exit();
}
$result = mdecrypt_generic($mcrypt, $data_to_decrypt);
echo PHP_EOL."decryption result|".$result.'|';
mcrypt_generic_deinit($mcrypt);
PS Не знаю почему, но Node.js игнорирует IV (в моем примере), поэтому шифр всегда будет одинаковым.PHP всегда использует IV, и он должен быть строгим, поэтому PHP всегда возвращает разные шифры.Но я попробовал наоборот (зашифрован PHP и расшифрован Node.js), и он работает.