将 PHP mcrypt() 调用转换为节点的 mcrypt
Converting a PHP mcrypt() call to node's mcrypt
我正在尝试使用 Node 的 mycrypt
模块将旧 PHP 应用程序中的加密功能重新创建到新的 Node JS 应用程序中。
我的目标是确保给定相同的原始字符串和盐,下面的 PHP 脚本生成与节点脚本相同的加密值。
PHP
<?php
$string = 'This is my password';
$salt = 'sodiumChloride12';
$encrypted = base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$salt,
$string,
MCRYPT_MODE_ECB,
mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND)
)
);
echo "Encrypted: $encrypted\n";
它产生:
Encrypted: iOKEAxaE4vIeWXBem01gHr2wdof7ZO2dld3BuR9l3Nw=
JavaScript
var mcrypt = require('mcrypt');
var MCrypt = mcrypt.MCrypt;
// Set algorithm and mode
var rijndaelEcb = new MCrypt('rijndael-128', 'ecb');
// Set up salt and IV
var salt = 'sodiumChloride12';
var iv = rijndaelEcb.generateIv();
rijndaelEcb.open(salt, iv);
/** ENCRYPTION **/
var cipher = rijndaelEcb.encrypt('This is my password');
var cipherConcat = Buffer.concat([iv, cipher]).toString('base64');
console.log('Encrypted: ' + cipherConcat);
/** DECRYPTION **/
// Convert back from base64
var ivAndCipherText = new Buffer(cipherConcat, 'base64');
// Undo concat of IV
var ivSize = rijndaelEcb.getIvSize();
iv = new Buffer(ivSize);
var cipherText = new Buffer(ivAndCipherText.length - ivSize);
ivAndCipherText.copy(iv, 0, 0, ivSize);
ivAndCipherText.copy(cipherText, 0, ivSize);
var plaintext = rijndaelEcb.decrypt(cipherText).toString();
console.log('Decrypted: ' + plaintext);
Node 版本产生:
Encrypted: 834aJoVRxla/fGNACUAVFYjihAMWhOLyHllwXptNYB69sHaH+2TtnZXdwbkfZdzc
Decrypted: This is my password
基于它解密了原始短语这一事实,我知道调用按预期工作,但加密输出与 PHP 脚本中的不同。解密逻辑来自 this answer,但我更关心的是使加密以相同的方式工作。
我在 Node 中对 IV 做的事情与在 PHP 中做的不同吗?
我查看了 ,但它使用 crypto
模块而不是我正在使用的 mcrypt
模块。
Am I doing something different with the IV in Node than in PHP?
嗯。密码是什么意思?
MCRYPT_MODE_ECB,
var rijndaelEcb = new MCrypt('rijndael-128', 'ecb');
您正在使用 ECB mode,它不使用 IV。您实际上是在浪费 CPU 个周期来生成一个。即使您使用的是 CBC 模式,MCRYPT_RAND
也是一个不好的常数。
var cipherConcat = Buffer.concat([iv, cipher]).toString('base64');
您将一个未使用的 IV 连接到您的密文,并抱怨无效结果? PHP 代码只是 returns cipher
(在 Node.js 等效术语中),而不是 iv
和 cipher
.
的串联
更重要的是,这里有一些严重的密码学缺陷需要解决,从上面提到的 ECB 模式开始:
- Do not encrypt passwords, use a password hashing algorithm. There's a huge difference.
- 如果您要加密,use authenticated encryption。
- Don't use mcrypt.
- 不要deploy home-grown crypto protocols into production or encourage other developers to do the same.
推荐步骤:
- 使用 PHP 解密您的数据,然后存储密码 properly。
- 如果您出于任何其他目的需要加密,use a high-level cryptography library,例如 libsodium。
我正在尝试使用 Node 的 mycrypt
模块将旧 PHP 应用程序中的加密功能重新创建到新的 Node JS 应用程序中。
我的目标是确保给定相同的原始字符串和盐,下面的 PHP 脚本生成与节点脚本相同的加密值。
PHP
<?php
$string = 'This is my password';
$salt = 'sodiumChloride12';
$encrypted = base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$salt,
$string,
MCRYPT_MODE_ECB,
mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND)
)
);
echo "Encrypted: $encrypted\n";
它产生:
Encrypted: iOKEAxaE4vIeWXBem01gHr2wdof7ZO2dld3BuR9l3Nw=
JavaScript
var mcrypt = require('mcrypt');
var MCrypt = mcrypt.MCrypt;
// Set algorithm and mode
var rijndaelEcb = new MCrypt('rijndael-128', 'ecb');
// Set up salt and IV
var salt = 'sodiumChloride12';
var iv = rijndaelEcb.generateIv();
rijndaelEcb.open(salt, iv);
/** ENCRYPTION **/
var cipher = rijndaelEcb.encrypt('This is my password');
var cipherConcat = Buffer.concat([iv, cipher]).toString('base64');
console.log('Encrypted: ' + cipherConcat);
/** DECRYPTION **/
// Convert back from base64
var ivAndCipherText = new Buffer(cipherConcat, 'base64');
// Undo concat of IV
var ivSize = rijndaelEcb.getIvSize();
iv = new Buffer(ivSize);
var cipherText = new Buffer(ivAndCipherText.length - ivSize);
ivAndCipherText.copy(iv, 0, 0, ivSize);
ivAndCipherText.copy(cipherText, 0, ivSize);
var plaintext = rijndaelEcb.decrypt(cipherText).toString();
console.log('Decrypted: ' + plaintext);
Node 版本产生:
Encrypted: 834aJoVRxla/fGNACUAVFYjihAMWhOLyHllwXptNYB69sHaH+2TtnZXdwbkfZdzc
Decrypted: This is my password
基于它解密了原始短语这一事实,我知道调用按预期工作,但加密输出与 PHP 脚本中的不同。解密逻辑来自 this answer,但我更关心的是使加密以相同的方式工作。
我在 Node 中对 IV 做的事情与在 PHP 中做的不同吗?
我查看了 crypto
模块而不是我正在使用的 mcrypt
模块。
Am I doing something different with the IV in Node than in PHP?
嗯。密码是什么意思?
MCRYPT_MODE_ECB,
var rijndaelEcb = new MCrypt('rijndael-128', 'ecb');
您正在使用 ECB mode,它不使用 IV。您实际上是在浪费 CPU 个周期来生成一个。即使您使用的是 CBC 模式,MCRYPT_RAND
也是一个不好的常数。
var cipherConcat = Buffer.concat([iv, cipher]).toString('base64');
您将一个未使用的 IV 连接到您的密文,并抱怨无效结果? PHP 代码只是 returns cipher
(在 Node.js 等效术语中),而不是 iv
和 cipher
.
更重要的是,这里有一些严重的密码学缺陷需要解决,从上面提到的 ECB 模式开始:
- Do not encrypt passwords, use a password hashing algorithm. There's a huge difference.
- 如果您要加密,use authenticated encryption。
- Don't use mcrypt.
- 不要deploy home-grown crypto protocols into production or encourage other developers to do the same.
推荐步骤:
- 使用 PHP 解密您的数据,然后存储密码 properly。
- 如果您出于任何其他目的需要加密,use a high-level cryptography library,例如 libsodium。