在 PHP 中加密字符串并在 Node.js 中解密
Posted
技术标签:
【中文标题】在 PHP 中加密字符串并在 Node.js 中解密【英文标题】:Encrypt string in PHP and decrypt in Node.js 【发布时间】:2013-11-24 21:52:40 【问题描述】:我通过 Apache 和 Node.js 服务器之间的不安全连接发送数据。我需要在 php 中加密数据并在 Node.js 中解密。我花了 2 天时间试图让它工作,但是我只设法让消息签名工作,没有加密。我尝试将 AES128-CBC、AES256-CBC、DES、AES128、AES256 作为算法传递,但效果不佳..
我在 PHP 中试过这个:
$data = json_encode(Array('mk' => $_SESSION['key'], 'algorithm' => 'SHA1', 'username' => $_SESSION['userid'], 'expires' => $expires));
$payload = openssl_encrypt($data, 'des', '716c26ef');
return base64_encode($payload);
在 Node.js 中:
var enc_json = new Buffer(response[1], 'base64');
var decipher = crypto.createDecipher('des', '716c26ef');
var json = decipher.update(enc_json).toString('ascii');
json += decipher.final('ascii');
除了错误的解密数据之外,我还会收到以下错误:
TypeError: error:0606508A:digital envelope routines:EVP_DecryptFinal_ex:data not multiple of block length
TypeError: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
我需要一个简单的加密,因为数据不太敏感(没有密码或用户数据),但是数据只能由接收者读取。密钥长度可以是任何值,但加密/解密过程必须尽可能简单,请不要使用 IV。
【问题讨论】:
为什么不能使用HTTPS? 你不应该返回base64_encode($payload);
吗?
@BenFortune 我是……我正在编辑问题的变量名称。
@ThiefMaster 这里面有第三方:数据到客户端,可以存储以备将来使用或立即发送到 Node.js 服务器。
这可能会有所帮助。 ***.com/questions/41181905/…
【参考方案1】:
这周我在同样的问题上苦苦挣扎,但以相反的方式(PHP 加密 -> NodeJS 解密)并设法让这个 sn-p 工作:
aes256cbc.js
var crypto = require('crypto');
var encrypt = function (plain_text, encryptionMethod, secret, iv)
var encryptor = crypto.createCipheriv(encryptionMethod, secret, iv);
return encryptor.update(plain_text, 'utf8', 'base64') + encryptor.final('base64');
;
var decrypt = function (encryptedMessage, encryptionMethod, secret, iv)
var decryptor = crypto.createDecipheriv(encryptionMethod, secret, iv);
return decryptor.update(encryptedMessage, 'base64', 'utf8') + decryptor.final('utf8');
;
var textToEncrypt = new Date().toISOString().substr(0,19) + '|My super secret information.';
var encryptionMethod = 'AES-256-CBC';
var secret = "My32charPasswordAndInitVectorStr"; //must be 32 char length
var iv = secret.substr(0,16);
var encryptedMessage = encrypt(textToEncrypt, encryptionMethod, secret, iv);
var decryptedMessage = decrypt(encryptedMessage, encryptionMethod, secret, iv);
console.log(encryptedMessage);
console.log(decryptedMessage);
aes256cbc.php
<?php
date_default_timezone_set('UTC');
$textToEncrypt = substr(date('c'),0,19) . "|My super secret information.";
$encryptionMethod = "AES-256-CBC";
$secret = "My32charPasswordAndInitVectorStr"; //must be 32 char length
$iv = substr($secret, 0, 16);
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secret,0,$iv);
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secret,0,$iv);
echo "$encryptedMessage\n";
echo "$decryptedMessage\n";
?>
这里避免陷入密钥/iv 大小/解密问题的秘诀是拥有恰好 32 个字符长度和 16 个字符长度的秘诀。 此外,在 NodeJS 中使用“base64”和“utf8”非常很重要,因为它们是 PHP 中的默认设置。
以下是一些示例运行:
$ node aes256cbc.js && php aes256cbc.php
zra3FX4iyCc7qPc1dZs+G3ZQ40f5bSw8P9n5OtWl1t86nV5Qfh4zNRPFbsciyyHyU3Qi4Ga1oTiTwzrPIZQXLw==
2015-01-27T18:29:12|My super secret information.
zra3FX4iyCc7qPc1dZs+G3ZQ40f5bSw8P9n5OtWl1t86nV5Qfh4zNRPFbsciyyHyU3Qi4Ga1oTiTwzrPIZQXLw==
2015-01-27T18:29:12|My super secret information.
$ node aes256cbc.js && php aes256cbc.php
zra3FX4iyCc7qPc1dZs+G6B6+8aavHNc/Ymv9L6Omod8Di3tMbvOa2B7O2Yiyoutm9fy9l0G+P5VJT9z2qNESA==
2015-01-27T18:29:15|My super secret information.
zra3FX4iyCc7qPc1dZs+G6B6+8aavHNc/Ymv9L6Omod8Di3tMbvOa2B7O2Yiyoutm9fy9l0G+P5VJT9z2qNESA==
2015-01-27T18:29:15|My super secret information.
$ node aes256cbc.js && php aes256cbc.php
zra3FX4iyCc7qPc1dZs+G4oD1Fr5yLByON6QDE56UOqP6kkfGJzpyH6TbwZYX2oGlh2JGv+aHYUMh0qQnAj/uw==
2015-01-27T18:29:29|My super secret information.
zra3FX4iyCc7qPc1dZs+G4oD1Fr5yLByON6QDE56UOqP6kkfGJzpyH6TbwZYX2oGlh2JGv+aHYUMh0qQnAj/uw==
2015-01-27T18:29:29|My super secret information.
$ node aes256cbc.js && php aes256cbc.php
zra3FX4iyCc7qPc1dZs+G5OVCbCaUy8a0LLF+Bn8UT4X3nYbtynO0Zt2mvXnnli9dRxrxMw43uWnkh8MIwVHXA==
2015-01-27T18:29:31|My super secret information.
zra3FX4iyCc7qPc1dZs+G5OVCbCaUy8a0LLF+Bn8UT4X3nYbtynO0Zt2mvXnnli9dRxrxMw43uWnkh8MIwVHXA==
2015-01-27T18:29:31|My super secret information.
$ node aes256cbc.js && php aes256cbc.php
fdsqSyHBJjlwD0jYfOUZM2FrONG6Fk5d7FOItYEdbnaZIhhmg/apa8/jPwKFkDXD9eNqWC3w0JzY5wjtZADiBA==
2015-01-27T18:30:08|My super secret information.
fdsqSyHBJjlwD0jYfOUZM2FrONG6Fk5d7FOItYEdbnaZIhhmg/apa8/jPwKFkDXD9eNqWC3w0JzY5wjtZADiBA==
2015-01-27T18:30:08|My super secret information.
$ node aes256cbc.js && php aes256cbc.php
fdsqSyHBJjlwD0jYfOUZM4SRfi6jG5EoDFEF6d9xCIyluXSiMaKlhd89ovpeOz/YyEIlPbYR4ly00gf6hWfKHw==
2015-01-27T18:30:45|My super secret information.
fdsqSyHBJjlwD0jYfOUZM4SRfi6jG5EoDFEF6d9xCIyluXSiMaKlhd89ovpeOz/YyEIlPbYR4ly00gf6hWfKHw==
2015-01-27T18:30:45|My super secret information.
注意:
我使用“时间戳|消息”格式来避免中间人攻击。例如,如果加密消息中包含要验证的 ID,则中间人可以捕获该消息并在每次他想重新验证时重新发送。
因此,我可以检查加密消息上的时间戳是否在一个小时间间隔内。这样一来,同一条消息由于时间戳的不同而每秒加密的方式不同,并且无法在这个固定的时间间隔之外使用。
编辑:
这里我误用了初始化向量 (IV)。
正如 @ArtjomB. 所解释的,IV 应该是加密消息的第一部分,并且它应该是一个随机值。
还建议在 HTTP 标头 (x-hmac: *value*
) 中使用 hmac
值,以验证消息是否来自有效来源(但这不能解决前面描述的“重新发送”消息问题)。
这是改进的版本,包括用于 php 和 node 的 hmac
以及作为加密消息一部分的 IV:
aes256cbc.js (v2)
var crypto = require('crypto');
var encrypt = function (message, method, secret, hmac)
//var iv = crypto.randomBytes(16).toString('hex').substr(0,16); //use this in production
var iv = secret.substr(0,16); //using this for testing purposes (to have the same encryption IV in PHP and Node encryptors)
var encryptor = crypto.createCipheriv(method, secret, iv);
var encrypted = new Buffer(iv).toString('base64') + encryptor.update(message, 'utf8', 'base64') + encryptor.final('base64');
hmac.value = crypto.createHmac('md5', secret).update(encrypted).digest('hex');
return encrypted;
;
var decrypt = function (encrypted, method, secret, hmac)
if (crypto.createHmac('md5', secret).update(encrypted).digest('hex') == hmac.value)
var iv = new Buffer(encrypted.substr(0, 24), 'base64').toString();
var decryptor = crypto.createDecipheriv(method, secret, iv);
return decryptor.update(encrypted.substr(24), 'base64', 'utf8') + decryptor.final('utf8');
;
var encryptWithTSValidation = function (message, method, secret, hmac)
var messageTS = new Date().toISOString().substr(0,19) + message;
return encrypt(messageTS, method, secret, hmac);
var decryptWithTSValidation = function (encrypted, method, secret, hmac, intervalThreshold)
var decrypted = decrypt(encrypted, method, secret, hmac);
var now = new Date();
var year = parseInt(decrypted.substr(0,4)), month = parseInt(decrypted.substr(5,2)) - 1,
day = parseInt(decrypted.substr(8,2)), hour = parseInt(decrypted.substr(11,2)),
minute = parseInt(decrypted.substr(14,2)), second = parseInt(decrypted.substr(17,2));
var msgDate = new Date(Date.UTC(year, month, day, hour, minute, second))
if (Math.round((now - msgDate) / 1000) <= intervalThreshold)
return decrypted.substr(19);
var message = 'My super secret information.';
var method = 'AES-256-CBC';
var secret = "My32charPasswordAndInitVectorStr"; //must be 32 char length
var hmac = ;
//var encrypted = encrypt(message, method, secret, hmac);
//var decrypted = decrypt(encrypted, method, secret, hmac);
var encrypted = encryptWithTSValidation(message, method, secret, hmac);
var decrypted = decryptWithTSValidation(encrypted, method, secret, hmac, 60*60*12); //60*60m*12=12h
console.log("Use HTTP header 'x-hmac: " + hmac.value + "' for validating against MitM-attacks.");
console.log("Encrypted: " + encrypted);
console.log("Decrypted: " + decrypted);
注意crypto.createHmac(...).digest('hex')
被hex
消化。这是 hmac
在 PHP 中的默认值。
aes256cbc.php (v2)
<?php
function encrypt ($message, $method, $secret, &$hmac)
//$iv = substr(bin2hex(openssl_random_pseudo_bytes(16)),0,16); //use this in production
$iv = substr($secret, 0, 16); //using this for testing purposes (to have the same encryption IV in PHP and Node encryptors)
$encrypted = base64_encode($iv) . openssl_encrypt($message, $method, $secret, 0, $iv);
$hmac = hash_hmac('md5', $encrypted, $secret);
return $encrypted;
function decrypt ($encrypted, $method, $secret, $hmac)
if (hash_hmac('md5', $encrypted, $secret) == $hmac)
$iv = base64_decode(substr($encrypted, 0, 24));
return openssl_decrypt(substr($encrypted, 24), $method, $secret, 0, $iv);
function encryptWithTSValidation ($message, $method, $secret, &$hmac)
date_default_timezone_set('UTC');
$message = substr(date('c'),0,19) . "$message";
return encrypt($message, $method, $secret, $hmac);
function decryptWithTSValidation ($encrypted, $method, $secret, $hmac, $intervalThreshold)
$decrypted = decrypt($encrypted, $method, $secret, $hmac);
$now = new DateTime();
$msgDate = new DateTime(str_replace("T"," ",substr($decrypted,0,19)));
if (($now->getTimestamp() - $msgDate->getTimestamp()) <= $intervalThreshold)
return substr($decrypted,19);
$message = "My super secret information.";
$method = "AES-256-CBC";
$secret = "My32charPasswordAndInitVectorStr"; //must be 32 char length
//$encrypted = encrypt($message, $method, $secret, $hmac);
//$decrypted = decrypt($encrypted, $method, $secret, $hmac);
$encrypted = encryptWithTSValidation($message, $method, $secret, $hmac);
$decrypted = decryptWithTSValidation($encrypted, $method, $secret, $hmac, 60*60*12); //60*60m*12=12h
echo "Use HTTP header 'x-hmac: $hmac' for validating against MitM-attacks.\n";
echo "Encrypted: $encrypted\n";
echo "Decrypted: $decrypted\n";
?>
以下是一些示例运行:
$ node aes256cbc.js && php aes256cbc.php
Use HTTP header 'x-hmac: 6862972ef0f463bf48523fc9e334bb42' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==I6cAKeoxeSP5TGgtK59PotB/iG2BUSU8Y6NhAhVabN9UB+ZCTn7q2in4JyLwQiGN
Decrypted: My super secret information.
Use HTTP header 'x-hmac: 6862972ef0f463bf48523fc9e334bb42' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==I6cAKeoxeSP5TGgtK59PotB/iG2BUSU8Y6NhAhVabN9UB+ZCTn7q2in4JyLwQiGN
Decrypted: My super secret information.
$ node aes256cbc.js && php aes256cbc.php
Use HTTP header 'x-hmac: b2e63f216acde938a82142220652cf59' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CSgYBBR8dkZytORm8xwEDmD9WB1mpqC3XnSrB+wR3/KW
Decrypted: My super secret information.
Use HTTP header 'x-hmac: b2e63f216acde938a82142220652cf59' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CSgYBBR8dkZytORm8xwEDmD9WB1mpqC3XnSrB+wR3/KW
Decrypted: My super secret information.
$ node aes256cbc.js && php aes256cbc.php
Use HTTP header 'x-hmac: 73181744453d55eb6f81896ffd284cd8' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CTGik4Lv9PnWuEg5SiADJcdKX1to0LrNKmuCiYIweBAZ
Decrypted: My super secret information.
Use HTTP header 'x-hmac: 73181744453d55eb6f81896ffd284cd8' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CTGik4Lv9PnWuEg5SiADJcdKX1to0LrNKmuCiYIweBAZ
Decrypted: My super secret information.
$ node aes256cbc.js && php aes256cbc.php
Use HTTP header 'x-hmac: 5372ecca442d65f582866cf3b24cb2b6' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CYEITF6aozBNp7bA54qY0Ugg9v6ktwoH6nqRyatkFqy8
Decrypted: My super secret information.
Use HTTP header 'x-hmac: 5372ecca442d65f582866cf3b24cb2b6' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==YsFRdKzCLuCk7Yg+U+S1CYEITF6aozBNp7bA54qY0Ugg9v6ktwoH6nqRyatkFqy8
Decrypted: My super secret information.
最后但同样重要的是,如果您没有在 php 中安装 openssl mod,您可以使用 mcrypt
代替 rijndael128
和 pkcs7
填充 (source),如下所示:
aes256cbc-mcrypt.php (v2)
<?php
function pkcs7pad($message)
$padding = 16 - (strlen($message) % 16);
return $message . str_repeat(chr($padding), $padding);
function pkcs7unpad($message)
$padding = ord(substr($message, -1)); //get last char and transform it to Int
return substr($message, 0, -$padding); //remove the last 'padding' string
function encrypt ($message, $method, $secret, &$hmac)
//$iv = substr(bin2hex(mcrypt_create_iv(mcrypt_get_iv_size($method, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM)),0,16); //use this in production
$iv = substr($secret, 0, 16); //using this for testing purposes (to have the same encryption IV in PHP and Node encryptors)
$message = pkcs7pad($message);
$encrypted = base64_encode($iv) . base64_encode(mcrypt_encrypt($method, $secret, $message, MCRYPT_MODE_CBC, $iv));
$hmac = hash_hmac('md5', $encrypted, $secret);
return $encrypted;
function decrypt ($encrypted, $method, $secret, $hmac)
if (hash_hmac('md5', $encrypted, $secret) == $hmac)
$iv = base64_decode(substr($encrypted, 0, 24));
return pkcs7unpad(mcrypt_decrypt($method, $secret , base64_decode(substr($encrypted, 24)) , MCRYPT_MODE_CBC, $iv));
function encryptWithTSValidation ($message, $method, $secret, &$hmac)
date_default_timezone_set('UTC');
$message = substr(date('c'),0,19) . "$message";
return encrypt($message, $method, $secret, $hmac);
function decryptWithTSValidation ($encrypted, $method, $secret, $hmac, $intervalThreshold)
$decrypted = decrypt($encrypted, $method, $secret, $hmac);
$now = new DateTime();
//echo "Decrypted: $decrypted\n";
$msgDate = new DateTime(str_replace("T"," ",substr($decrypted,0,19)));
if (($now->getTimestamp() - $msgDate->getTimestamp()) <= $intervalThreshold)
return substr($decrypted,19);
$message = "My super secret information.";
$method = MCRYPT_RIJNDAEL_128;
$secret = "My32charPasswordAndInitVectorStr"; //must be 32 char length
//$encrypted = encrypt($message, $method, $secret, $hmac);
//$decrypted = decrypt($encrypted, $method, $secret, $hmac);
$encrypted = encryptWithTSValidation($message, $method, $secret, $hmac);
$decrypted = decryptWithTSValidation($encrypted, $method, $secret, $hmac, 60*60*12); //60*60m*12=12h
echo "Use HTTP header 'x-hmac: $hmac' for validating against MitM-attacks.\n";
echo "Encrypted: $encrypted\n";
echo "Decrypted: $decrypted\n";
?>
当然,接下来是一些测试:
$ php aes256cbc-mcrypt.php && node aes256cbc.js
Use HTTP header 'x-hmac: 801282a9ed6b2d5bd2254140d7a17582' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==ipQ+Yah8xoF0C6yjCJr8v9IyatyGeNT2yebrpJZ5xH73H5fFcV1zhqhRGwM0ToGU
Decrypted: My super secret information.
Use HTTP header 'x-hmac: 801282a9ed6b2d5bd2254140d7a17582' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==ipQ+Yah8xoF0C6yjCJr8v9IyatyGeNT2yebrpJZ5xH73H5fFcV1zhqhRGwM0ToGU
Decrypted: My super secret information.
$ php aes256cbc-mcrypt.php && node aes256cbc.js
Use HTTP header 'x-hmac: 0ab2bc83108e1e250f6ecd483cd65329' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==ipQ+Yah8xoF0C6yjCJr8v79P+j4YUl8ln8eu7FDqEdbxMe1Z7BvW8iVUN1qFCiHM
Decrypted: My super secret information.
Use HTTP header 'x-hmac: 0ab2bc83108e1e250f6ecd483cd65329' for validating against MitM-attacks.
Encrypted: YjE0ZzNyMHNwVm50MGswbQ==ipQ+Yah8xoF0C6yjCJr8v79P+j4YUl8ln8eu7FDqEdbxMe1Z7BvW8iVUN1qFCiHM
Decrypted: My super secret information.
【讨论】:
IV 不应该是秘密的。通常,它在加密过程中被添加到密文中,并在解密过程中被切掉。此外,如果您的情况可能发生中间人攻击,您应该在密文上使用 HMAC 等经过身份验证的加密,或直接使用 GCM 等经过身份验证的模式。 @ArtjomB。感谢您的澄清!我已经修改了我的代码以添加 IV,添加了hmac
验证,并试图澄清我试图描述的中间人场景。你现在怎么看?谢谢!伊格纳西奥
为我节省了数小时的时间!【参考方案2】:
在处理这样的对称加密时,第一步是意识到这可能会给后面带来巨大的痛苦 - 我从来没有,曾经让它立即工作,即使我在复制粘贴我自己的代码.这主要是因为加密和解密方法在设计上是完全无情的,并且很少给出有用的错误消息。单个空字符、回车、换行或动态转换的类型可以默默地破坏整个过程。
了解这一点,逐步前进。我建议如下:
首先,让 PHP 单独工作。传入示例文本,对其进行加密,立即解密,并将其与原始明文变量严格相等进行比较。它们完全一样吗?同时输出两者 - 它们是同一类型并且看起来完全不受干扰吗?注意未打印的字符 - 还要检查长度和字符编码!
现在,使用比前一个多或少 1 个字符的示例文本执行上述操作。这可以调试块大小/零填充问题 - 这很重要。
如果这有效 - 并且很少立即有效,出于难以预测的原因,请继续使用 Node.js。
在 Node.js 中,执行与在 PHP 中相同的操作,即使这看起来是白费力气 - 出于其他原因,稍后会很明显。在您的 Node.js 中一起加密和解密。它是否适用于上述所有相同的附带条件?
一旦完成,“有趣”的部分就来了:在 Node.js 和 PHP 中独立使用相同的加密方法,让它们都向您输出两者都生成的“最终”准备好传输的密码文本。
如果一切顺利,它们应该是完美的,完全相同的。如果不是,则您的加密实现和方法在系统之间不兼容存在问题。某些设置错误或冲突(可能使用零填充或许多其他可能性,或 IV 等),或者您需要尝试不同的实现。
如果我不得不盲目猜测,我会说 base64 编码和解码存在问题(这是最常见的问题)。事情往往要完成两次,因为在 Web 应用程序中调试二进制数据类型(通过浏览器)可能很棘手。有时事物被编码两次但只解码一次,或者一个实现将“有用地”自动编码/解码某些东西而不清楚它正在做什么,等等。
这也可能是 Node 和 PHP 之间的零填充实现问题,如下所示:AES encrypt in Node.js Decrypt in PHP. Fail.
您的错误代码强烈建议最后两个问题。加密方法预测精确长度的块大小,如果它们关闭,则表明传递给函数的数据损坏 - 如果一个额外的字符滑入,或者编码处理方式不同等,就会发生这种情况。
如果您一次完成上述每个步骤,确保自己不能急于求成,并且必须检查过程中每一个艰苦的微小步骤,那么应该更清楚到底哪里出了问题,然后可以排除故障。
【讨论】:
很好的答案,非常彻底 这可能比给出代码清单要好。加上阅读后,除了更多的测试和调试之外,似乎没有“答案”可以解决我的问题。非常感谢。 不客气!如果你深入了解它的更新会很棒 - 如果没有别的我想知道我的直觉是否接近或者它是否完全不同。当它工作时真的很有趣,但是对称加密真的可以从你的一天/一周/一个月中抽出一口,即使你没有跨过这样的系统。当然,如果您将范围缩小一点,请随时使用更多代码提出另一个问题(在此处交叉发布“后续问题”的链接很方便)。【参考方案3】:这是codeiginiter框架默认解密等效js脚本(aes128cbc),希望对大家有所帮助。
let crypto = require("crypto");
let secret = 'xxxxxxxxxxxxxxxxxxxx';
// ikm is initial keying material
var hkdf = function (hashAlg, salt, ikm)
this.hashAlg = hashAlg;
// create the hash alg to see if it exists and get its length
var hash = crypto.createHash(this.hashAlg);
this.hashLength = hash.digest().length;
this.salt = salt || new Buffer(this.hashLength).fill(0).toString();
this.ikm = ikm;
// now we compute the PRK
var hmac = crypto.createHmac(this.hashAlg, this.salt);
hmac.update(this.ikm);
this.prk = hmac.digest();
;
hkdf.prototype =
derive: function(info, size, cb)
var prev = new Buffer(0);
var output;
var buffers = [];
var num_blocks = Math.ceil(size / this.hashLength);
info = new Buffer(info);
for (var i=0; i<num_blocks; i++)
var hmac = crypto.createHmac(this.hashAlg, this.prk);
hmac.update(prev);
hmac.update(info);
hmac.update(new Buffer([i + 1]));
prev = hmac.digest();
buffers.push(prev);
output = Buffer.concat(buffers, size);
return output;
;
function decrypt(code)
if (typeof code !== 'string')
return false;
code = code.substring(128);
var buff = new Buffer(code, 'base64');
var iv = buff.slice(0, 16);
var encyptedText = buff.slice(16).toString('base64');
var _hkdf = new hkdf('sha512', null, secret);
var derive_key = _hkdf.derive('encryption', secret.length);
var key = derive_key.slice(0, 16);
var decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
var result = decipher.update(encyptedText, 'base64');
result += decipher.final();
return result.replace(/[']/g, '');
【讨论】:
【参考方案4】:基于 @inieto 的回答,我创建了两个简单的加密和解密类,一个用于 php,另一个用于易于使用的 typescript . https://github.com/5imun/Endecryptor 只需包含/导入它们,您就可以开始了。 php示例:
#Include Endecryptor before using it
$secret = 'hxXxVEVNa3S6OQdgltNoDkbZ10b0MkQV';
$method = 'AES-256-CBC';
$valid_request_TS_interval = 100; # in seconds
$endecryptor = new Endecryptor($secret, $method, $valid_request_TS_interval );
$original_message = '"test":"Hello, World!"';
$endecryptor->encryptWithTS($original_message);
echo "Encrypted message: $endecryptor->temp_encrypted\n";
echo "Encrypted message hmac: $endecryptor->temp_hmac\n";
if ( $endecryptor->decryptAndValidateTS( $endecryptor->temp_encrypted, $endecryptor->temp_hmac ) )
echo "Original message: $original_message\n";
echo "Decrypted message: $endecryptor->temp_decrypted\n";
else
echo 'Description was not successful';
结果:
Encrypted message: MjliMmM5NzljYWQ0YjA4Mw==ULxsH1juCOrieEkiRpHY1CMkKtvSvB5X+b8E9cOcQ7yYt+SUKj+I6FjaGvYjEldt
Encrypted message: hmac: 5aa8f1b268dfef0dc2f48f1a25204e82
Original message: "test":"Hello, World!"
Decrypted message: "test":"Hello, World!"
【讨论】:
以上是关于在 PHP 中加密字符串并在 Node.js 中解密的主要内容,如果未能解决你的问题,请参考以下文章
Node.js 和 webcrypto 之间的 RSA 加密