Nodejs javascript implementation of PBEWithMD5AndTripleDES/CBC/PKCS5Padding

前端 未结 2 940
轻奢々
轻奢々 2021-01-01 06:15

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 {         


        
2条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-01 06:51

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

    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('', '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

    To explain a little what's going on:

    • 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.

提交回复
热议问题