使用 CakePHP 3.0 加密并使用 NodeJS 解密
Encrypt with CakePHP 3.0 and decrypt with NodeJS
我使用 CakePHP 3.0 框架开发了管理站点,我使用默认 Security::encrypt($text, $key, $hmacSalt = null) 来加密令牌以获得 API 授权。
我也有用于实时通信的简单 NodeJS 服务,我想对 API 和这种实时通信使用相同的令牌。
我尝试用不同的方式将 CakePHP 解密函数重写为 NodeJS,但我无法获得正确的结果。下面是 CakePHP 解密函数:
public static function decrypt($cipher, $key)
{
$method = 'AES-256-CBC';
$ivSize = openssl_cipher_iv_length($method);
$iv = mb_substr($cipher, 0, $ivSize, '8bit');
echo "---- IV --- \r\n";
var_dump($iv);
$cipher = mb_substr($cipher, $ivSize, null, '8bit');
echo "---- KEY --- \r\n";
var_dump($key);
echo "---- CIPHER LAST --- \r\n";
var_dump($cipher);
return openssl_decrypt($cipher, $method, $key, OPENSSL_RAW_DATA, $iv);
}
蛋糕的结果PHP:
---- IV ---
string(16) "��r�N3U�Y6Q�#��"
---- KEY ---
string(32) "1c494314996afe280bc5981c4e185f79"
---- CIPHER LAST ---
string(160) "~a�xh�z��+���M����j*!�(����f�ZG;�)w��Kl�3�m��Z��ە��OR9~���6[X�/��n��B6��C��˟f��!6��1���|S��*�mG+���OR�kr��t�;�+�㟱��"���<i����e:��"
这是我在 NodeJS 中的简单代码:
var buf = new Buffer(socket.handshake.query.token, 'base64').toString('utf8', 64);
var iv = buf.substr(0,16);
console.log("-----IV------")
console.log(iv);
var key = sha256(config.tokenKey+config.tokenSalt).substr(0,32);
console.log("-----KEY------")
console.log(key);
var cipher = buf.substr(16);
console.log("------CIPHER-----");
console.log(cipher);
var decipher = crypto.createDecipheriv('AES-256-CBC', key, iv);
//decipher.setAutoPadding(false);
var dec = decipher.update(cipher);
dec += decipher.final('utf-8');
NodeJS 的结果:
-----IV------
��r�N3U�Y6Q�#��
-----KEY------
1c494314996afe280bc5981c4e185f79
------CIPHER-----
~a�xh�z��+���M���
��j*!�(����f�ZG;�)w��Kl��m���Z����ە��OR9~���6[X�/��n��B6��C��˟f���!6��1���|S��*�mG+���OR�kr��t�;�+�㟱��"���<i����e:��
crypto.js:239
this._handle.initiv(cipher, toBuf(key), toBuf(iv));
Error: Invalid IV length
我尝试以不同的方式创建 IV,但它不起作用,即使我成功避免了异常,我也没有得到正确的结果,我假设问题出在 PHP 代码中的“8 位”编码中。
如果有人知道如何解决这个问题,我将不胜感激!
我对 Node.js 不太熟悉,但我看到的是,当您将输入转换为 UTF-8 字符串时,您搞砸了数据,您需要处理二进制数据,不带字符串。
我建议在您真正需要将某些内容转换为字符串之前使用缓冲区,至少当我不得不解密使用 CakePHP 加密的数据时我是这样做的:
var data = Buffer.from(socket.handshake.query.token, 'base64');
var key = config.tokenKey;
var salt = config.tokenSalt;
var hmacSize = 64;
var ivSize = 16;
var keySize = 32;
var encrypted = data.slice(hmacSize);
key = crypto
.createHash('sha256')
.update(key + salt)
.digest('hex')
.substr(0, keySize);
var iv = encrypted.slice(0, ivSize);
encrypted = encrypted.slice(ivSize);
var decipher = crypto.createDecipheriv('AES-256-CBC', key, iv);
var decrypted = Buffer.concat([
decipher.update(encrypted),
decipher.final()
]);
console.log(decrypted.toString('utf8'));
我使用 CakePHP 3.0 框架开发了管理站点,我使用默认 Security::encrypt($text, $key, $hmacSalt = null) 来加密令牌以获得 API 授权。
我也有用于实时通信的简单 NodeJS 服务,我想对 API 和这种实时通信使用相同的令牌。
我尝试用不同的方式将 CakePHP 解密函数重写为 NodeJS,但我无法获得正确的结果。下面是 CakePHP 解密函数:
public static function decrypt($cipher, $key)
{
$method = 'AES-256-CBC';
$ivSize = openssl_cipher_iv_length($method);
$iv = mb_substr($cipher, 0, $ivSize, '8bit');
echo "---- IV --- \r\n";
var_dump($iv);
$cipher = mb_substr($cipher, $ivSize, null, '8bit');
echo "---- KEY --- \r\n";
var_dump($key);
echo "---- CIPHER LAST --- \r\n";
var_dump($cipher);
return openssl_decrypt($cipher, $method, $key, OPENSSL_RAW_DATA, $iv);
}
蛋糕的结果PHP:
---- IV ---
string(16) "��r�N3U�Y6Q�#��"
---- KEY ---
string(32) "1c494314996afe280bc5981c4e185f79"
---- CIPHER LAST ---
string(160) "~a�xh�z��+���M����j*!�(����f�ZG;�)w��Kl�3�m��Z��ە��OR9~���6[X�/��n��B6��C��˟f��!6��1���|S��*�mG+���OR�kr��t�;�+�㟱��"���<i����e:��"
这是我在 NodeJS 中的简单代码:
var buf = new Buffer(socket.handshake.query.token, 'base64').toString('utf8', 64);
var iv = buf.substr(0,16);
console.log("-----IV------")
console.log(iv);
var key = sha256(config.tokenKey+config.tokenSalt).substr(0,32);
console.log("-----KEY------")
console.log(key);
var cipher = buf.substr(16);
console.log("------CIPHER-----");
console.log(cipher);
var decipher = crypto.createDecipheriv('AES-256-CBC', key, iv);
//decipher.setAutoPadding(false);
var dec = decipher.update(cipher);
dec += decipher.final('utf-8');
NodeJS 的结果:
-----IV------
��r�N3U�Y6Q�#��
-----KEY------
1c494314996afe280bc5981c4e185f79
------CIPHER-----
~a�xh�z��+���M���
��j*!�(����f�ZG;�)w��Kl��m���Z����ە��OR9~���6[X�/��n��B6��C��˟f���!6��1���|S��*�mG+���OR�kr��t�;�+�㟱��"���<i����e:��
crypto.js:239
this._handle.initiv(cipher, toBuf(key), toBuf(iv));
Error: Invalid IV length
我尝试以不同的方式创建 IV,但它不起作用,即使我成功避免了异常,我也没有得到正确的结果,我假设问题出在 PHP 代码中的“8 位”编码中。
如果有人知道如何解决这个问题,我将不胜感激!
我对 Node.js 不太熟悉,但我看到的是,当您将输入转换为 UTF-8 字符串时,您搞砸了数据,您需要处理二进制数据,不带字符串。
我建议在您真正需要将某些内容转换为字符串之前使用缓冲区,至少当我不得不解密使用 CakePHP 加密的数据时我是这样做的:
var data = Buffer.from(socket.handshake.query.token, 'base64');
var key = config.tokenKey;
var salt = config.tokenSalt;
var hmacSize = 64;
var ivSize = 16;
var keySize = 32;
var encrypted = data.slice(hmacSize);
key = crypto
.createHash('sha256')
.update(key + salt)
.digest('hex')
.substr(0, keySize);
var iv = encrypted.slice(0, ivSize);
encrypted = encrypted.slice(ivSize);
var decipher = crypto.createDecipheriv('AES-256-CBC', key, iv);
var decrypted = Buffer.concat([
decipher.update(encrypted),
decipher.final()
]);
console.log(decrypted.toString('utf8'));