【发布时间】:2015-04-15 01:50:33
【问题描述】:
借助 node-rijndael 模块,我让 Node.js 解密了一个 php AES-256-cbs 加密字符串,但我无法使用外部提供的十六进制共享密钥对其进行正确加密。 以下是使用节点 node-rijndael 解密 php AES-256-cbs https://stackoverflow.com/a/25107892/2141980
的信息我很接近了,只是节点加密的结果中混入了一些垃圾字符
//-- file: rijndael.js (just a wrapper module for node-rijndael) --
var Rijndael = require('node-rijndael');
function rtrim(string, chr) {
for (var i = string.length - 1; i >= 0; i--)
if (string[i] !== chr)
return string.slice(0, i + 1);
return '';
}
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;
}
function encrypt (text_in, input_key, input_iv) {
var rijndael = new Rijndael(input_key, {
mode: Rijndael.MCRYPT_MODE_CBC,
encoding: 'hex',
iv: input_iv
});
var padded = rpad(text_in, '\0', Rijndael.blockSize);
return rijndael.encrypt(padded , 'binary', 'base64');
}
function decrypt (ciphertext, input_key, input_iv) {
var rijndael = new Rijndael(input_key, {
mode: Rijndael.MCRYPT_MODE_CBC,
encoding: 'hex', // shared_key encoding ignored if a buffer */
iv: input_iv
});
return rtrim(rijndael.decrypt(ciphertext, 'base64', 'binary'), '\0');
}
exports.decrypt = decrypt;
exports.encrypt = encrypt;
/-- END file: rijndael.js --
// Star here:
// include the above wrapper module:
var rijndael = require('rijndael');
var crypto = require('crypto');
// can use, set Rijndael encoding to 'hex'
var key = '24 8b 2d c7 3e 98 0b 3b 5b 9a 93 1e 41 e6 a1 43 70 dd 06 c7 1e a9 c9 67 ce d8 36 00 52 66 3b 49';
key = key.replace(/ /g, '');
var plain_text = "DANGER WILL ROBINSON...A horse is a horse of course...Lucy, you've got some explaining to do...Marsha Marsha Marsha";
var aes_iv = crypto.randomBytes(32).toString('base64');
// in: binary, out: base64
var encrypted = rijndael.encrypt (plain_text, key, aes_iv);
console.log("encrypted, base64:\n" + encrypted);
// in: base64, out: binary
var back_again = rijndael.decrypt (encrypted, key, aes_iv);
console.log("decrypted :" + back_again);
console.log("typeof: " + typeof back_again);
/* php version of above
$shared_secret_key = '24 8b 2d c7 3e 98 0b 3b 5b 9a 93 1e 41 e6 a1 43 70 dd 06 c7 1e a9 c9 67 ce d8 36 00 52 66 3b 49';
$shared_secret_key = str_replace(' ', '', $shared_secret_key);
$shared_secret_key = pack('H*', $shared_secret_key);
$plain_text = "DANGER WILL ROBINSON...A horse is a horse of course...Lucy, you've got some explaining to do...Marsha Marsha Marsha";
// generate 32 byte random binary string
$aes_iv = mcrypt_create_iv(32, MCRYPT_RAND);
// encrypt:
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $shared_secret_key, $plain_text, MCRYPT_MODE_CBC, $aes_iv);
$encrypted_encoded = base64_encode($encrypted );
echo $encrypted_encoded; # compare with Node.js
// decrypt:
$response = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $shared_secret_key, $encrypted , MCRYPT_MODE_CBC, $aes_iv);
$response = rtrim($response, "\0"); // AES adds null characters to the end of short strings, so we should strip them out
echo "\n", $response;
*/
【问题讨论】:
-
能否包含完整的加密数据?如果没有实验能力,就很难诊断出这个问题。
-
好的,我也会从外部 php 源获得完整的演示十六进制密钥。
-
我确实注意到它是我的节点的前 32 个字符被解密,节点加密包含垃圾字符,所以如果我留下填充字符串用 32 个虚拟字符加密,那么我可以砍掉解密字符串的前 32 个字符。但我不能指望外部服务器这样做。外部 php 加密 -> 节点解密(工作)然后节点加密响应并发送到外部 php 进行解密
-
添加了完整的加密数据和十六进制密钥
-
我的解决方案是在创建新的 Rijndael 对象时将十六进制密钥转换为 base64 并将密钥编码选项设置为 base64。
标签: javascript php node.js encryption cryptography