如何在nodejs应用程序中创建相当于php代码的openssl加密和解密
How to create openssl encryption and decryption equivalent of php code in nodejs application
我在 php 上有一个应用程序 运行,它使用以下代码使用 openssl encrption 加密了一些值
<?php
define('OSSLENCKEY','14E2E2D1582A36172AE401CB826003C1');
define('OSSLIVKEY', '747E314D23DBC624E971EE59A0BA6D28');
function encryptString($data) {
$encrypt_method = "AES-256-CBC";
$key = hash('sha256', OSSLENCKEY);
$iv = substr(hash('sha256', OSSLIVKEY), 0, 16);
$output = openssl_encrypt($data, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
return $output;
}
function decryptString($data){
$encrypt_method = "AES-256-CBC";
$key = hash('sha256', OSSLENCKEY);
$iv = substr(hash('sha256', OSSLIVKEY), 0, 16);
$output = openssl_decrypt(base64_decode($data), $encrypt_method, $key, 0, $iv);
return $output;
}
echo encryptString("Hello World");
echo "<br>";
echo decryptString("MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09");
?>
我有另一个在 nodejs 上运行的端点,我需要根据上述 php encrypt/decrypt 规则解密和加密值。
我已搜索但找不到解决方案。
我尝试使用库 crypto
但最终出现错误 Reference
我试过的nodejs代码如下
message = 'MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09';
const cypher = Buffer.from(message, "base64");
const key = crypto.createHash('sha256').update('14E2E2D1582A36172AE401CB826003C1');//.digest('hex');
// $iv = substr(hash('sha256', '747E314D23DBC624E971EE59A0BA6D28'), 0, 16); from php returns '0ed9c2aa27a31693' need nodejs equivalent
const iv = '0ed9c2aa27a31693';
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
console.log( decipher.update(contents) + decipher.final());
求大神帮我找一个openssl加密解密的nodejs代码
提前致谢
代码中存在以下问题:
- 密钥以 PHP 代码中的十六进制编码返回,因此在 AES-256 的 NodeJS 代码中,密钥必须只考虑前 32 个字节(PHP 会自动执行此操作) .
- PHP 代码 Base64 隐式编码密文,因此由于显式 Base64 编码,密文被 Base64 编码两次(这是不必要的)。因此,在NodeJS代码中也需要双重Base64编码。
此外,请注意,使用静态 IV 是不安全的(但您这样做可能只是为了测试目的)。
以下 NodeJS 代码生成与 PHP 代码相同的密文:
const crypto = require('crypto');
const plain = 'Hello World';
const hashKey = crypto.createHash('sha256');
hashKey.update('14E2E2D1582A36172AE401CB826003C1');
const key = hashKey.digest('hex').substring(0, 32);
const hashIv = crypto.createHash('sha256');
hashIv.update('747E314D23DBC624E971EE59A0BA6D28');
const iv = hashIv.digest('hex').substring(0, 16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
var encrypted = cipher.update(plain, 'utf-8', 'base64');
encrypted += cipher.final('base64');
encrypted = Buffer.from(encrypted, 'utf-8').toString('base64');
console.log(encrypted); // MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09
encrypted = Buffer.from(encrypted, 'base64').toString('utf-8');
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
var decrypted = decipher.update(encrypted, 'base64', 'utf-8');
decrypted += decipher.final('utf-8');
console.log(decrypted); // Hello World
编辑:
如评论中所述,PHP的hash()
方法returns hash默认为十六进制字符串(除非第三个参数明确设置为true
,参考代码中不是这种情况)。这使长度加倍,因为在这种编码中,哈希的每个字节都由两个十六进制数字(hexits)表示,即 2 个字节。
因此有必要缩短 NodeJS 代码中的密钥(请参阅我的原始答案的第一点)。这种缩短在 PHP 代码中是不必要的,因为 PHP 这样做 隐式 (这实际上是一个设计缺陷,因为这样用户就不会注意到密钥可能有问题)。
使用十六进制字符串有两个缺点:
- 对于十六进制编码的字符串,每个字节包含 16 个可能的值 (0-15),而不是一个字节的 256 个可能的值 (0-255)。这将安全性从 256 位降低到 128 位(在算术上等同于 AES-128),请参阅 here。
- 根据平台的不同,十六进制 a-f 可以表示为小写或大写字母,这可能导致不同的密钥和 IV(没有对两种情况之一的明确约定)。
出于这些原因,使用哈希的原始二进制数据比使用十六进制编码的字符串更安全、更可靠。如果你想这样做,那么下面的改变是必要的。
在PHP代码中:
$key = hash('sha256', OSSLENCKEY, true);
$iv = substr(hash('sha256', OSSLIVKEY, true), 0, 16);
在 NodeJS 代码中:
const key = hashKey.digest();
const iv = hashIv.digest().slice(0, 16)
但是请注意,此版本与旧版本不兼容,即更改前的加密无法在更改后解密。所以旧数据必须迁移。
我在 php 上有一个应用程序 运行,它使用以下代码使用 openssl encrption 加密了一些值
<?php
define('OSSLENCKEY','14E2E2D1582A36172AE401CB826003C1');
define('OSSLIVKEY', '747E314D23DBC624E971EE59A0BA6D28');
function encryptString($data) {
$encrypt_method = "AES-256-CBC";
$key = hash('sha256', OSSLENCKEY);
$iv = substr(hash('sha256', OSSLIVKEY), 0, 16);
$output = openssl_encrypt($data, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
return $output;
}
function decryptString($data){
$encrypt_method = "AES-256-CBC";
$key = hash('sha256', OSSLENCKEY);
$iv = substr(hash('sha256', OSSLIVKEY), 0, 16);
$output = openssl_decrypt(base64_decode($data), $encrypt_method, $key, 0, $iv);
return $output;
}
echo encryptString("Hello World");
echo "<br>";
echo decryptString("MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09");
?>
我有另一个在 nodejs 上运行的端点,我需要根据上述 php encrypt/decrypt 规则解密和加密值。 我已搜索但找不到解决方案。
我尝试使用库 crypto
但最终出现错误 Reference
我试过的nodejs代码如下
message = 'MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09';
const cypher = Buffer.from(message, "base64");
const key = crypto.createHash('sha256').update('14E2E2D1582A36172AE401CB826003C1');//.digest('hex');
// $iv = substr(hash('sha256', '747E314D23DBC624E971EE59A0BA6D28'), 0, 16); from php returns '0ed9c2aa27a31693' need nodejs equivalent
const iv = '0ed9c2aa27a31693';
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
console.log( decipher.update(contents) + decipher.final());
求大神帮我找一个openssl加密解密的nodejs代码
提前致谢
代码中存在以下问题:
- 密钥以 PHP 代码中的十六进制编码返回,因此在 AES-256 的 NodeJS 代码中,密钥必须只考虑前 32 个字节(PHP 会自动执行此操作) .
- PHP 代码 Base64 隐式编码密文,因此由于显式 Base64 编码,密文被 Base64 编码两次(这是不必要的)。因此,在NodeJS代码中也需要双重Base64编码。
此外,请注意,使用静态 IV 是不安全的(但您这样做可能只是为了测试目的)。
以下 NodeJS 代码生成与 PHP 代码相同的密文:
const crypto = require('crypto');
const plain = 'Hello World';
const hashKey = crypto.createHash('sha256');
hashKey.update('14E2E2D1582A36172AE401CB826003C1');
const key = hashKey.digest('hex').substring(0, 32);
const hashIv = crypto.createHash('sha256');
hashIv.update('747E314D23DBC624E971EE59A0BA6D28');
const iv = hashIv.digest('hex').substring(0, 16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
var encrypted = cipher.update(plain, 'utf-8', 'base64');
encrypted += cipher.final('base64');
encrypted = Buffer.from(encrypted, 'utf-8').toString('base64');
console.log(encrypted); // MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09
encrypted = Buffer.from(encrypted, 'base64').toString('utf-8');
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
var decrypted = decipher.update(encrypted, 'base64', 'utf-8');
decrypted += decipher.final('utf-8');
console.log(decrypted); // Hello World
编辑:
如评论中所述,PHP的hash()
方法returns hash默认为十六进制字符串(除非第三个参数明确设置为true
,参考代码中不是这种情况)。这使长度加倍,因为在这种编码中,哈希的每个字节都由两个十六进制数字(hexits)表示,即 2 个字节。
因此有必要缩短 NodeJS 代码中的密钥(请参阅我的原始答案的第一点)。这种缩短在 PHP 代码中是不必要的,因为 PHP 这样做 隐式 (这实际上是一个设计缺陷,因为这样用户就不会注意到密钥可能有问题)。
使用十六进制字符串有两个缺点:
- 对于十六进制编码的字符串,每个字节包含 16 个可能的值 (0-15),而不是一个字节的 256 个可能的值 (0-255)。这将安全性从 256 位降低到 128 位(在算术上等同于 AES-128),请参阅 here。
- 根据平台的不同,十六进制 a-f 可以表示为小写或大写字母,这可能导致不同的密钥和 IV(没有对两种情况之一的明确约定)。
出于这些原因,使用哈希的原始二进制数据比使用十六进制编码的字符串更安全、更可靠。如果你想这样做,那么下面的改变是必要的。
在PHP代码中:
$key = hash('sha256', OSSLENCKEY, true);
$iv = substr(hash('sha256', OSSLIVKEY, true), 0, 16);
在 NodeJS 代码中:
const key = hashKey.digest();
const iv = hashIv.digest().slice(0, 16)
但是请注意,此版本与旧版本不兼容,即更改前的加密无法在更改后解密。所以旧数据必须迁移。