将PHP mcrypt()调用转换为node';s mcrypt


Converting a PHP mcrypt() call to node's mcrypt

我正试图使用Node的mycrypt模块,将旧PHP应用程序中的加密函数重新创建为新的Node JS应用程序。

我的目标是确保给定相同的原始字符串和salt,下面的PHP脚本生成与Node脚本相同的加密值。


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脚本中的不同。解密逻辑来自这个答案,但我更关心的是让加密以同样的方式工作。

Node中的IV和PHP中的IV有什么不同吗?

我看了这个问题,但它使用了crypto模块,而不是我正在使用的mcrypt模块。

Node中的IV和PHP中的IV有什么不同吗?

嗯。代码上写着什么?

MCRYPT_MODE_ECB,

var rijndaelEcb = new MCrypt('rijndael-128', 'ecb');

你使用的是ECB模式,它不使用IV。你实际上是在浪费CPU周期来生成一个。即使您使用CBC模式,MCRYPT_RAND也是一个不适合在这里使用的常量。

var cipherConcat = Buffer.concat([iv, cipher]).toString('base64');

你把一个未使用的IV连接到你的密文上,并抱怨结果无效?PHP代码只是返回cipher(用Node.js的等效术语来说),而不是ivcipher的串联。


更重要的是,这里有一些严重的密码学缺陷需要解决,从上面提到的ECB模式开始:

  1. 不要加密密码,请使用密码哈希算法。这是一个巨大的差异
  2. 如果要加密,请使用经过身份验证的加密
  3. 不要使用mcrypt
  4. 不要将本土加密协议部署到生产中,也不要鼓励其他开发人员也这样做

推荐步骤:

  1. 使用PHP解密您的数据,然后正确存储密码
  2. 如果您出于任何其他目的需要加密,请使用高级密码库,如libsodium