Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在PHP中加密字符串并在Node.js中解密_Javascript_Php_Json_Node.js_Encryption - Fatal编程技术网

Javascript 在PHP中加密字符串并在Node.js中解密

Javascript 在PHP中加密字符串并在Node.js中解密,javascript,php,json,node.js,encryption,Javascript,Php,Json,Node.js,Encryption,我通过Apache和Node.js服务器之间的不安全连接发送数据。我需要在PHP中加密数据,在Node.js中解密。我花了两天时间试图让它工作,但我只设法让消息签名工作,没有加密。我尝试将AES128-CBC、AES256-CBC、DES、AES128、AES256作为算法传递,但没有任何结果 我在PHP中尝试过: $data = json_encode(Array('mk' => $_SESSION['key'], 'algorithm' => 'SHA1', 'username'

我通过Apache和Node.js服务器之间的不安全连接发送数据。我需要在PHP中加密数据,在Node.js中解密。我花了两天时间试图让它工作,但我只设法让消息签名工作,没有加密。我尝试将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

我需要一个简单的加密,因为数据不是太敏感(没有密码或用户数据),但数据应该只由收件人读取。密钥长度可以是任意长度,但加密/解密过程必须尽可能简单,请不要使用IVs。

当处理像这样的对称加密时,第一步是意识到这可能会是一个巨大的后遗症-我从来没有,从来没有让它立即工作过,即使是在我复制粘贴自己的代码时。这主要是因为加密和解密方法在设计上是完全不可原谅的,很少给出有用的错误消息。单个空字符、回车符、换行符或动态转换的类型可能会悄悄地破坏整个过程

知道这一点,就要循序渐进。我建议如下:

首先,让PHP单独工作。传入示例文本,对其进行加密,立即解密,并将其与原始明文变量进行严格相等的比较。它们完全一样吗?输出两个,以及-他们是相同的类型,并显示完全不受干扰?注意非打印字符-检查长度和字符编码

现在,使用一个比上一个多或少1个字符的示例文本执行上述操作。这会调试块大小/零填充问题-这很重要

如果这是可行的——而且由于难以预测的原因,它很少立即起作用,请继续使用Node.js

在Node.js中,做与在PHP中相同的事情,即使这看起来像是白费力气——因为额外的原因,这一点很明显。在Node.js中一起加密和解密。它是否适用于上述所有相同的但书

完成后,接下来是“有趣”的部分:在Node.js和PHP中分别使用相同的加密方法,让它们向您输出两个生成的“最终”准备传输的CryptText

如果一切顺利,它们应该完全一样。如果它们不兼容,则说明您的加密实现和方法在系统之间不兼容。某些设置错误或冲突(可能是零填充或大量其他可能性,或IV等),或者您需要尝试不同的实现

如果我不得不盲目猜测,我会说base64编码和解码存在问题(这是最常见的错误)。事情往往要做两次,因为在web应用程序中调试二进制数据类型(通过浏览器)可能很棘手。有时事情被编码两次,但只被解码一次,或者一个实现将“有益地”自动编码/解码一些东西,而不清楚它正在做什么,等等

也可能是节点和PHP之间的零填充实现问题,如下所示:

您的错误代码强烈建议了最后两个问题。加密方法预测精确长度的块大小,如果禁用,则表示传递给函数的数据已损坏-如果插入一个额外字符,或如果编码处理方式不同,则会发生这种情况,等等


如果你一次一步地完成上面的每一个步骤,确保自己不会仓促行事,并且必须检查过程中每一个艰难的小步骤,那么应该更清楚地知道到底哪里出了问题,然后才能排除故障。

我本周也在努力解决同样的问题,但情况正好相反(PHP encrypts->NodeJS decrypts)并设法使此代码段正常工作:

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";
?>
注意:

我使用一个“时间戳消息”格式来避免中间人攻击。例如,如果加密的消息包含要被认证的ID,则MITM可以捕获消息并在每次想要重新认证时重新发送它。 因此,我可以检查加密消息上的时间戳是否在一个小的时间间隔内。这样,由于时间戳的原因,同一消息每秒的加密方式不同,并且不能在这个固定的时间间隔外使用

编辑:

这里我误用了初始化向量(IV)。 正如@ArtjomB.所解释的,IV应该是加密消息的第一部分,并且应该是一个随机值。 还建议在HTTP头中使用
hmac
值(
x-hmac:*值*
),以验证消息是否源自有效源(但这并不能解决前面描述的“重新发送”消息问题)

以下是改进的版本,包括用于php和node的
hmac
,以及作为加密消息一部分的IV:

aes256cbc.js(v2)

以下是一些运行示例:

$ 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.
$ 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
填充(),如下所示:

aes256cbc-mcrypt.php(v2)


这是CodeIgniter框架默认解密等价的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, '');
}
let crypto=require(“crypto”);
保密='xxxxxxxxxxxxxxxxx';
//ikm是初始键控材料
var hkdf=函数(hashAlg、salt、ikm){
this.hashAlg=hashAlg;
//创建哈希alg以查看它是否存在并获取其长度
var hash=crypto.createHash(this.has
$ 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

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.
 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, '');
}
#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!"}