Node.js javascript实现PBEWithMD5AndTripleDES / CBC / PKCS5Padding [英] Nodejs javascript implementation of PBEWithMD5AndTripleDES/CBC/PKCS5Padding

查看:1502
本文介绍了Node.js javascript实现PBEWithMD5AndTripleDES / CBC / PKCS5Padding的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了编写一个简单的nodejs应用程序与以java编写的服务器交谈,我必须为nodejs实现以下功能。

In order to write an simple nodejs app talking to an server written in java I have to implement the following functionality for nodejs.

public class Crypto {
  Cipher decipher;

  byte[] salt = {
      (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
      (byte) 0x0A, (byte) 0x0B, (byte) 0x0C, (byte) 0x0D
  };
  int iterationCount = 10;

  public Crypto(String pass) {
    try {
      KeySpec keySpec = new PBEKeySpec(pass.toCharArray(), salt, iterationCount);

      SecretKey key = SecretKeyFactory.getInstance(
          "PBEWithMD5AndTripleDES").generateSecret(keySpec);

      ecipher = Cipher.getInstance("PBEWithMD5AndTripleDES/CBC/PKCS5Padding");

      AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

      decipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

    } catch (Exception ex) {
    }
  }
}

我使用 crypto 模块nodejs

var crypto = require('crypto'),
      pass = new Buffer(wek),
      salt = new Buffer([0x01, 0x02, 0x03, 0x04, 0x0A, 0x0B, 0x0C, 0x0D])
      password = 'mySecretPassword'
      key = crypto.pbkdf2(pass, salt, 10, 256)
      cipher, 
      encrypted;

cipher = crypto.createCipher('des-ede-cbc', key);
encrypted = cipher.update(new Buffer('the very secred information'));

在将加密信息发送到服务器后,我无法使用 decipher 上面的java代码示例中列出的对象。我认为主要的问题是 md5 部分。我不能弄清楚如何使用 crypto nodejs 模块实现。有没有人想法如何解决这个问题?

After sending the encrypted information to the server, I can't decrypt the message with the decipher Object as listed in the java code sample above. I think the main problem is the md5 part. I can't figure out how to implement that with the crypto nodejs module. Has anyone an idea how to solve this problem? Or is ther any other module or library to achieve that?

编辑:我为nodejs尝试了另一个模块: node-forge

I tried another module for nodejs: node-forge

forge = require('node-forge')

var numIterations = 10,
      keyLength = 24,
      password = forge.util.createBuffer('mySecretPassword'),
      salt = new forge.util.ByteBuffer(new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x0A, 0x0B, 0x0C, 0x0D])),
      derivedKey = forge.pkcs5.pbkdf2(password, salt.getBytes(), numIterations, keyLength, forge.md.md5.create())
      iv = {}; // TODO... ???

var cipher = forge.des.createEncryptionCipher(derivedKey);
cipher.start(iv);
cipher.update('the very secred information');
cipher.finish();
var encrypted = cipher.output;

但我有几个问题/问题:

But I have several problems/questions:


  • 我在javascript中使用正确的算法吗?

  • salt

  • 如何在Java实现中生成初始化向量?在 node-forge 的最后一个代码示例中,我必须在上提供 iv 开始(iv)。在java代码中我看不出这是怎么做的。在我看来, iv 在客户端和服务器上必须相同,否则是不正确的?

  • Do I use the correct algorithm in javascript?
  • Is the salt calculation match with the java implementation?
  • How can I determine which keyLength is used in the java implementation?
  • How is the initialization vector generated in the java implementation? In the last code sample with node-forgeI have to provide the iv on cipher.start(iv). In the java code I can't see how this is done. In my opinion the iv must be the same on client and server or is this incorrect?

推荐答案

我对com.sun.crypto.provider.PBES1Core#derivCipherKey();

I reverse engineered the DESede part of the key derivation function found at com.sun.crypto.provider.PBES1Core#deriveCipherKey();

我们在Java服务器中使用Jasypt作为加密库,我们的node.js服务器能够使用这个加密和解密。我希望它有帮助(写在ES2015,运行在节点v4.0.0及以上):

We use Jasypt as encryption library in a Java server and our node.js server is able to encrypt and decrypt with this. I hope it helps (Written in ES2015, runs in node v4.0.0 and up):

'use strict';
var crypto = require('crypto');

class Encryption {
    constructor() {
        this.privateKey = new Buffer('<your password>', 'utf-8');
    }

    encrypt(message) {
        var salt = crypto.randomBytes(8);
        var key = this._generateKey(this.privateKey, salt);
        var cipher = crypto.createCipheriv('des-ede3-cbc', this._subBuf(key, 0, 24), this._subBuf(key, 24));
        var result = cipher.update(message, 'utf-8', 'hex');
        return salt.toString('hex') + result + cipher.final('hex');
    }

    decrypt(message) {
        var salt = new Buffer(message.substr(0, 16), 'hex');
        var key = this._generateKey(this.privateKey, salt);
        message = message.substr(16);
        var decipher = crypto.createDecipheriv('des-ede3-cbc', this._subBuf(key, 0, 24), this._subBuf(key, 24));
        var result = decipher.update(message, 'hex', 'utf-8');
        return result + decipher.final('utf-8');
    }

    _generateKey(password, salt) {
        if (!(password instanceof Buffer)) {
            throw new Error('Password needs to be a buffer');
        }
        if (!(salt instanceof Buffer) || salt.length != 8) {
            throw new Error('Salt needs to be an 8 byte buffer');
        }

        var iterations;
        for(iterations = 0; iterations < 4 && salt[iterations] == salt[iterations + 4]; ++iterations) {}

        if(iterations == 4) {
            for(iterations = 0; iterations < 2; ++iterations) {
                var tmp = salt[iterations];
                salt[iterations] = salt[3 - iterations];
                salt[2] = tmp; // Seems like an error that we have to live with now
            }
        }

        var result = new Buffer(32);
        for(iterations = 0; iterations < 2; ++iterations) {
            var intermediate = new Buffer(salt.length / 2);
            for (let i = 0; i < salt.length / 2; i++) {
                intermediate[i] = salt[iterations * (salt.length / 2) + i];
            }

            for(let i = 0; i < 1000; ++i) {
                var hash = crypto.createHash('md5');
                hash.update(intermediate);
                hash.update(password);
                intermediate = hash.digest();
            }

            for (let i = 0; i<intermediate.length; i++) {
                result[i + (iterations * 16)] = intermediate[i];
            }
        }
        return result;
    }

    _subBuf(buffer, start, length) {
        if (!length) {
            length = buffer.length - start;
        }
        var result = new Buffer(length, 'hex');
        for (let i = 0; i < length; i++) {
            result[i] = buffer[i + start]
        }
        return result;
    }
}

要解释一下发生了什么:

To explain a little what's going on:


  • 加密的邮件以十六进制格式返回,其他可能更适合您的实现。


  • 使用的密钥是32字节长度,假设前24个字节是TripleDES和最后8个的键是盐

  • 生成的邮件带有用于加密邮件的随机生成的盐。

  • 根据你的JVM的安全设置,你可能没有实际使用des-ede3(cbc似乎是固定的设置)。

  • Encrypted messages are returned in hex format, something else might fit your implementation better.
  • The _generateKey() is a direct copy from the java source.
  • The keys used are 32 byte length and assume that the first 24 bytes are the keys for TripleDES and the last 8 are the salt
  • The generated message is prefixed with the random generated salt that used to encrypt the message.
  • Depending on the security settings of your JVM it might be possible that you are not actually using des-ede3 (cbc seems to be a fixed setting). You should definitely double check if this works with your setup.

这里可能需要清除一些代码,但至少应该得到你开始在正确的方向。

Some code clean up might be necessary here, but it should at least get you started in the right direction.

这篇关于Node.js javascript实现PBEWithMD5AndTripleDES / CBC / PKCS5Padding的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆