我發現了幾件事情,這可能是原因爲什麼PHP和Node.js的加密/解密是不一樣的。
PHP使用了MCRYPT_RIJNDAEL_256 algorythm。 AES 256基於MCRYPT_RIJNDAEL_256,但不一樣。 AES 256這是加密標準,但不是算法。
如果您嘗試使用標準簡單函數(例如PHP上的「mcrypt_encrypt」和「mcrypt_decrypt」)對某些內容進行加密,則無法看到所有步驟,並且您肯定無法知道爲什麼不能解密你所加密的內容。它可以與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 - 它是加密/解密的函數。我發現它here。
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([email protected]_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);
P.S. 我不知道爲什麼,但Node.js忽略IV(在我的例子中),所以密碼將永遠是相同的。 PHP總是使用IV,它應該是嚴格的長度,所以PHP總是返回不同的密碼。但我反過來試了一下(由PHP加密並由Node.js解密),並且它工作正常。
我必須保持密鑰32字節嗎? – murvinlai 2011-05-18 16:43:53
它不起作用。我曾嘗試在node.js中使用AES-256進行加密。然後使用具有相同32字節密鑰的RJ-128進行解密,並且使用16字節的iv。仍然失敗。 – murvinlai 2011-05-18 17:45:41
加密後的加密數據是base64編碼的。這就是爲什麼它有所作爲? – murvinlai 2011-05-18 19:16:21