【问题标题】:Node.js/javascript encrypt AES-128 like mcrypt_ecb in PHPNode.js/javascript 像 PHP 中的 mcrypt_ecb 一样加密 AES-128
【发布时间】:2015-10-07 07:45:47
【问题描述】:

我有一个用 AES-128 加密 IP 地址的 PHP 代码:

$ip = "MY_IP";
$secret = "MY_KEY";
$ip = @mcrypt_ecb(MCRYPT_RIJNDAEL_128, $secret, $ip, MCRYPT_ENCRYPT); 
$encrypted = bin2hex($ip);  // encrypted: 2854edb405cb7230ba1f4b87acddba8a

我需要做的是拥有相同的代码,但使用 javascript/node.js。我在 crypto node.js 本机模块中进行了搜索,但无法重现相同的结果:

var crypto = require('crypto');
var ip = "MY_IP";
var secret = "MY_KEY";
var cipher = crypto.createCipher("AES-128-ECB", secret);
var encrypted = cipher.update(ip, 'utf8', 'hex');
encrypted += cipher.final('hex'); // encrypted: e84c06888696edda0139e98fc2c0a8cc

有人有想法吗?

【问题讨论】:

  • 停止使用@ 隐藏错误。它掩盖了问题。
  • 连接是什么?此外,这个 php 代码不是我的,所以你的评论没有帮助。
  • 这种联系是不好的做法,会导致难以追踪的错误发生。如果你做任何 PHP 工作,几乎在所有情况下都避免使用 @ 运算符。

标签: javascript php node.js encryption


【解决方案1】:

我发的太快了,找到解决办法了:

$> npm install mcrypt

然后是代码:

var MCrypt = require('mcrypt').MCrypt;
var ip = "MY_IP";
var secret = "MY_KEY"
var desEcb = new MCrypt('rijndael-128', 'ecb');
desEcb.open(secret);
var cipherText = desEcb.encrypt(ip); // cipherText: 2854edb405cb7230ba1f4b87acddba8a

MCrypt github获取更多加密工具:https://github.com/tugrul/node-mcrypt

【讨论】:

    【解决方案2】:

    这里的问题是 PHP 的 mcrypt 扩展(和节点的 createCipher())在幕后做了一些你可能不知道的事情。

    首先,createCipher() 接受使用 MD5 散列的“密码”以派生 实际 密钥。因此,您应该使用 createCipheriv(),它允许您直接传递密钥(和 IV),就像 PHP 的 mcrypt 接受一样。在 ECB 模式下,IV 被忽略,因此您只需为 IV 参数传入一个空字符串。

    其次,如果它们分别小于密码的块大小和密钥大小,PHP 的 mcrypt 会神奇地用空字节填充 both 您的输入 您的密钥。 p>

    所以对于 AES-128-ECB,我们需要确保输入和密钥长度是 16 字节的倍数。有了所有这些知识,我们就会发现内置 crypto 模块的适当代码可能类似于:

    var crypto = require('crypto');
    
    function makePadded(str) {
      var buf;
      var len = str.length;
      if (str.length % 16)
        len = str.length + (16 - str.length % 16);
      buf = new Buffer(len);
      buf.fill(0);
      buf.write(str, 0, str.length);
      return buf;
    }
    
    var ip = makePadded('MY_IP');
    var secret = makePadded('MY_KEY');
    var cipher = crypto.createCipheriv("AES-128-ECB", secret, '');
    var encrypted = cipher.update(ip, 'binary', 'hex');
    encrypted += cipher.final('hex');
    // Slice off at 16 bytes to match the input length
    encrypted = encrypted.slice(0, 32);
    
    console.log(encrypted);
    

    最后值得一提的是,PHP 中的MCRYPT_RIJNDAEL_128 可用于进行 128、192 或 256 位加密。所以在 PHP 中如果0 < keylen <= 16 将使用 128 位加密,如果16 < keylen <= 24 将使用 192 位加密,如果24 < keylen <= 32 将使用 256 位加密。但是在 node 中,您需要适当地调整密码名称,因为 node 不会像 PHP 那样进行“自动调整”。

    【讨论】:

    • 嗯,我从你的回答中学到了很多东西。同时我在 var cipher = crypto.createCipheriv("AES-128-ECB", secret, ''); 上遇到错误==> crypto.js:346 this._binding.initiv(cipher, toBuf(key), toBuf(iv));错误:错误:0607A082:数字信封例程:EVP_CIPHER_CTX_set_key_length:无效密钥长度
    • 您的密钥大小是多少?也是十六进制编码的吗?
    • 它是 32 并以 utf-8 编码。此外,在你的解决方案和我在 npm 上找到的 mcrypt 包的使用之间,你觉得哪种解决方案最好?
    • 如果您的密钥大小为 32 字节长,那么您应该改用 AES-256-ECB。您还需要将 makePaddedslice(0, 32) 中的 16 更改为 32 到 slice(0, 64)
    【解决方案3】:

    在 nodejs 中 - 密码必须是“二进制”编码的字符串或缓冲区。在 PHP 中,已弃用的 @mcrypt_ecb 期望密钥是字符串

    【讨论】:

    • 也许以二进制形式传递密码会起作用,但我更喜欢使用我找到的包,它不使用不稳定的本机加密模块
    猜你喜欢
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    相关资源
    最近更新 更多