Php Node.js AES-256-CBC加密问题
我试图根据PHP中给出的一个示例代码创建一个加密字符串,我的主要问题是Node.jsPhp Node.js AES-256-CBC加密问题,php,node.js,openssl,cryptography,Php,Node.js,Openssl,Cryptography,我试图根据PHP中给出的一个示例代码创建一个加密字符串,我的主要问题是Node.jscrypto模块不接受长度超过32字节的密钥,但PHPopenssl\u encrypt接受,这似乎就是我得到无效密钥大小错误的原因 以下是我的js代码: let iv = sha1(await HelpersService.makeRandomNumber(null, null, 16)); iv = iv.substr(0, 16); const text = bundledData;
crypto
模块不接受长度超过32字节的密钥,但PHPopenssl\u encrypt
接受,这似乎就是我得到无效密钥大小错误的原因
以下是我的js代码:
let iv = sha1(await HelpersService.makeRandomNumber(null, null, 16));
iv = iv.substr(0, 16);
const text = bundledData;
const password = sha1(this.credentials.appSecret);
let salt = sha1(await HelpersService.makeRandomNumber(null, null, 4));
salt = salt.substr(0, 4);
const key = crypto.createHash('sha256').update(password + salt).digest('hex');
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encoded = cipher.update(text, 'utf8', 'hex');
encoded += cipher.final('hex');
这是PHP示例:
function generateCashOutAPIHashKey($app_secret ){
//remove plus(+) sign from gsm number.
$data = 'text';
$iv = substr(sha1(mt_rand()), 0, 16);
$password = sha1($app_secret);
$salt = substr(sha1(mt_rand()), 0, 4);
$saltWithPassword = hash('sha256', $password . $salt);
$encrypted = openssl_encrypt("$data", 'aes-256-cbc', "$saltWithPassword", null, $iv );
return $encrypted;
}
PHP和NodeJS代码中生成的密钥长度为64字节。使用的加密AES-256需要一个32字节的密钥。在PHP代码中,隐式地将64字节键缩短为32字节。在NodeJS代码中,必须明确执行以下操作:
另外,openssl\u encrypt()
返回默认编码的密文Base64。在NodeJS代码中,结果返回十六进制编码。在这里,您必须在update()
和final()
调用中将输出编码从'hex'
更改为'base64'
:
let encoded = cipher.update(text, 'utf8', 'base64');
encoded += cipher.final('base64');
请注意,PHP参考代码有许多漏洞:
- 不是加密安全的伪随机数生成器(CSPRNG)。PHP提供加密安全的方法来派生随机IV/salt,例如or
- 使用SHA-256推断密钥。使用可靠的密钥派生函数(例如)更安全。4字节通常太小
- 在大多数情况下被认为是不安全的,不能再使用
有人对以下问题有疑问吗
crypto.createHash('sha256')。更新(密码+
盐)。消化('hex')。substr(0,32)
我理解需要由sha256生成的32字节值的意图,但如果您对字符串进行十六进制编码,然后获取字符串的前32个字符,则会显著降低该值。现在有一个32个字符长的字符串,每个字符只有16个可能的值(0-9a-f)。您确实需要一个32字节的值,每个字节有256个可能的值。您已将加密密钥的密钥安全性从预期的256^32(1.1E77)更改为16^32(3.4E38)
crypto.createHash('sha256')。update('')。digest('hex')
“e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855”
crypto.createHash('sha256')。update('')。digest('hex')。substr(0,32)
‘e3b0c44298fc1c149afbf4c8996fb924’
找到一种使用SHA256生成的字节值的方法。小的可能不相关的点当作为参数传递时,例如
openssl\u encrypt($data“,
a simpleopenssl\u encrypt),您不需要将变量放在引号中($data,
就足够了HP根据指定的算法隐式截断密钥长度,即AES-256为32字节。NodeJS代码的加密模块不会自动执行此操作,因此必须使用substr(0,32)显式截断密钥
。此外,PHP代码返回加密文本Base64编码,即在NodeJS代码中,必须在update()
和final()中更改输出编码
从'hex'
打电话到'base64'
@Topaco非常感谢!现在一切都好了。你能发布它吗?我会将它标记为回答不客气。我将它作为回答发布。@Gray非常感谢,实际上我明白你的意思,但我只是第三方服务的消费者,他们打算创建这样的密钥,我只是模拟代码,但如果我想在未来做同样的加密,我肯定会考虑你的观点。
let encoded = cipher.update(text, 'utf8', 'base64');
encoded += cipher.final('base64');