0

I'm trying to use the aes-256-cbc-hmac-sha1 algorithm with the Node.js crypto module.

Here's a code snippet showing what I'm trying to do:

// adapted from http://stackoverflow.com/a/6046913

var crypto = require('crypto');
var data = "I am the clear text data";
console.log('Original cleartext: ' + data);

// //// WORKS
// var algorithm = 'aes-128-cbc';
// var keyBuffer = crypto.randomBytes(16);
// var ivBuffer = crypto.randomBytes(16);

// DOES NOT WORK
var algorithm = 'aes-256-cbc-hmac-sha1';
var keyBuffer = crypto.randomBytes(32);
var ivBuffer = crypto.randomBytes(16);

// var algorithm = 'aes-256-cfb8';       // ok
// var keyBuffer = crypto.randomBytes(32);
// var ivBuffer = crypto.randomBytes(16);

// var algorithm = 'aes-128-cbc-hmac-sha1'; // fail
// var keyBuffer = crypto.randomBytes(16);
// var ivBuffer = crypto.randomBytes(16);

var clearEncoding = 'utf8';
var cipherEncoding = 'hex';

var cipher = crypto.createCipheriv(algorithm, keyBuffer, ivBuffer);
var cipherChunks = [];
cipherChunks.push(cipher.update(data, clearEncoding, cipherEncoding));
cipherChunks.push(cipher.final(cipherEncoding));

console.log('ciphertext', cipherChunks.join(''));

var decipher = crypto.createDecipheriv(algorithm, keyBuffer, ivBuffer);
var plainChunks = [];

//// all at once
// var encrypted = cipherChunks.join('');
// plainChunks.push(decipher.update(encrypted, cipherEncoding, clearEncoding));

//// in pieces
for (var i = 0; i < cipherChunks.length;i++) {
  plainChunks.push(decipher.update(cipherChunks[i], cipherEncoding, clearEncoding));
}
plainChunks.push(decipher.final(clearEncoding));

// var pt = plainChunks.join('');

var pt = '';
for (i = 0; i < plainChunks.length; i++) pt += plainChunks[i].toString(clearEncoding);

console.log("UTF8 plaintext deciphered: " + pt);
console.log('GOOD with ' + algorithm + '?', pt === data);

The algorithms without an included HMAC work, but the HMAC ones don't. It fails on the decipher.update step. Full output:

Original cleartext: I am the clear text data
ciphertext 364ddcface495bcc4e7c8c895443143a632a98d0942b8c844d53db7d770fabca

crypto.js:279
  var ret = this._binding.update(data, inputEncoding);
                          ^
TypeError: error:00000000:lib(0):func(0):reason(0)
    at Decipheriv.Cipher.update (crypto.js:279:27)
    at Object.<anonymous> (../../crypto-example.js:44:29)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

If I create an HMAC by itself, however, it works fine:

var crypto = require('crypto');
var data = "I am the clear text data";
var algorithm = 'sha1';
var keyBuffer = crypto.randomBytes(32);
var hmac = crypto.createHmac(algorithm, keyBuffer);
hmac.update(data);
var hash = hmac.digest('hex');
console.log('hash', hash);

Any ideas what I'm doing wrong? Or is this a bug in the crypto module? (Tested with node 0.10.26 and 0.10.28, same result.)

Thank you

(Note, also posted this as a bug: https://github.com/joyent/node/issues/7583)

gevorg
  • 4,273
  • 4
  • 32
  • 49
thebuckst0p
  • 534
  • 1
  • 5
  • 13

1 Answers1

-1

The cipher part is just aes-256-cbc part. The hmac part is just hmac-sha1.

You have to create two objects, the cipher/decipher instance and the hmac instance. Use the output from the cipher/decipher instance with the hmac instance to create a hash for verification purposes.

The aes-256-cbc-hmac-sha1 is just used to identify a cipher/verification/etc. combination and is not an actual cipher itself.

mscdex
  • 93,083
  • 13
  • 170
  • 135
  • "aes-256-cbc-hmac-sha1" shows up in the list returned by crypto.getCiphers(). So it certainly appears to be an actual cipher... I don't think your statement is correct. – thebuckst0p May 07 '14 at 21:54
  • Also, it encrypts just fine, it just has trouble decrypting. If it wasn't a cipher, I would expect it to fail on encrypt as well. – thebuckst0p May 07 '14 at 22:48