Basic failing example:
const iv = crypto.randomBytes(16);
const salt = "foobar";
const hash = crypto.createHash("sha1");
hash.update(salt);
let key = hash.digest("binary");
key = key.substring(0, 16);
key.length // 16
const cipher = crypto.createCipheriv('aes-128-cbc', key, iv); //uncaughtException: Invalid key length
Passing in a binary encoded string with a length of 16
causes the last line to throw. Adding more or removing bytes has no effect.
Passing a utf8 encoded line with a length of 16
doesn't throw.
This behaviour showed up with Node v6 (v5 worked fine).
The default string encoding used by the crypto
module changed in v6.0.0 from binary
to utf8
. So your binary string is being interpreted as utf8 and is most likely becoming larger than 16 bytes during that conversion process (rather than smaller than 16 bytes) due to invalid utf8 character bytes being added.
Interesting. Based on your information, I was able to work around this by creating a Buffer
from the binary-encoded string:
const iv = crypto.randomBytes(16);
const salt = "foobar";
const hash = crypto.createHash("sha1");
hash.update(salt);
let key = Buffer.from(hash.digest("binary").substring(0, 16), "binary");//buffer from binary string.
const cipher = crypto.createCipheriv('aes-128-cbc', key, iv); //works
Is this the recommended method of what I'm trying to do? Or am I over-complicating it?
Yes, you want to use a Buffer, but you don't need to deal with binary strings at all here, just do this:
const iv = crypto.randomBytes(16);
const salt = "foobar";
const hash = crypto.createHash("sha1");
hash.update(salt);
// `hash.digest()` returns a Buffer by default when no encoding is given
let key = hash.digest().slice(0, 16);
const cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
Ah! Much simpler. Thank you so much for your help.
Most helpful comment
Yes, you want to use a Buffer, but you don't need to deal with binary strings at all here, just do this: