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 {
My final solution 5 years ago was:
var forge = require('node-forge');
var crypto = require('crypto');
var base64Coder = require('./utils/tac-base64coder');
var ByteBuffer = forge.util.ByteBuffer;
var DES_EDE_KEY_LEN = 24;
var DES_BLOCK_SIZE = 8;
var SALT_BYTES = [0x45, 0xC4, 0x31, 0x72, 0x8A, 0x62, 0xB3, 0x9A];
var KEY_BUFFER_LENGTH = 24;
var IV_BUFFER_LENGTH = 8;
module.exports = {
/**
* Generates the derived key. The 16 bytes of the first digest and the 1st 8 bytes of the 2nd digest
* form the triple DES key, and the last 8 bytes of the 2nd digest form the IV.
*
* @method _deriveCipherKey
* @param {String} key The key phrase
* @param {Int8Array} salt The salt
* @param {Number} iCount The iteration count
* @returns {Buffer}
* @private
*/
_deriveCipherKey: function _deriveCipherKey (key, salt, iCount) {
var md;
var passwdBytes = new Buffer(key);
var i;
var toBeHashed;
var result = new Buffer(DES_EDE_KEY_LEN + DES_BLOCK_SIZE);
result.fill(0);
// if the 2 salt halves are the same, invert one of them
for (i = 0; i < 4; i++) {
if (salt[i] !== salt[i + 4]) {
break;
}
}
if (i === 4) { // same, invert 1st half
for (i = 0; i < 2; i++) {
var tmp = salt[i];
salt[i] = salt[3 - i];
salt[3 - 1] = tmp;
}
}
for (i = 0; i < 2; i++) {
toBeHashed = new Buffer(salt.length / 2);
toBeHashed.fill(0);
salt.copy(toBeHashed, 0, i * (salt.length / 2));
for (var j = 0; j < iCount; j++) {
md = crypto.createHash('md5');
md.update(toBeHashed);
md.update(passwdBytes);
toBeHashed = md.digest();
}
toBeHashed.copy(result, i * 16);
}
return result;
},
/**
* Encrypts the given string with the given key
*
* @method encrypt
* @param {String} encryptionKey The encryption key
* @param {String} toEncrypt The string to encrypt
* @returns {String}
*/
encrypt: function encrypt (encryptionKey, toEncrypt) {
var encodedStr = forge.util.encodeUtf8(toEncrypt);
var salt = new Buffer(SALT_BYTES);
var key = new Buffer(KEY_BUFFER_LENGTH);
var iv = new Buffer(IV_BUFFER_LENGTH);
var key2 = new ByteBuffer();
var iv2 = new ByteBuffer();
var derivedKey = this._deriveCipherKey(encryptionKey, salt, 12);
var cipher;
var i = 0;
derivedKey.copy(key, 0, 0, 24);
derivedKey.copy(iv, 0, 24);
for (; i < KEY_BUFFER_LENGTH; i++) {
key2.putByte(key[i]);
}
for (i = 0; i < IV_BUFFER_LENGTH; i++) {
iv2.putByte(iv[i]);
}
cipher = forge.des.createEncryptionCipher(key2);
cipher.start(iv2);
cipher.update(forge.util.createBuffer(encodedStr));
cipher.finish();
return base64Coder.encode(cipher.output.getBytes().toString());
},
/**
* Decrypts the given base64 string with the given key
*
* @method decrypt
* @param {String} encryptionKey The decryption key
* @param {String} toDecrypt The encrypted base64 string
* @returns {String}
*/
decrypt: function decrypt (encryptionKey, toDecrypt) {
var decr = forge.util.decode64(toDecrypt);
var salt = new Buffer(SALT_BYTES);
var key = new Buffer(KEY_BUFFER_LENGTH);
var iv = new Buffer(IV_BUFFER_LENGTH);
var derivedKey = this._deriveCipherKey(encryptionKey, salt, 12);
var key2 = new forge.util.ByteBuffer();
var iv2 = new forge.util.ByteBuffer();
var i = 0;
var cipher;
derivedKey.copy(key, 0, 0, 24);
derivedKey.copy(iv, 0, 24);
for (; i < KEY_BUFFER_LENGTH; i++) {
key2.putByte(key[i]);
}
for (i = 0; i < IV_BUFFER_LENGTH; i++) {
iv2.putByte(iv[i]);
}
cipher = forge.des.createDecryptionCipher(key2);
cipher.start(iv2);
cipher.update(forge.util.createBuffer(decr));
cipher.finish();
return cipher.output.getBytes().toString('utf8');
}
};