Node: "Invalid key length" when generating a cipher from binary encoded string

Created on 11 May 2016  路  4Comments  路  Source: nodejs/node

  • version: v.6.1.0
  • platforms:

    • 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05 PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64

    • Linux 3.13.0-29-generic # 53-Ubuntu SMP Wed Jun 4 21:00:20 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

  • module affected: crypto

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

crypto

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:

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);

All 4 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

TazmanianDI picture TazmanianDI  路  127Comments

speakeasypuncture picture speakeasypuncture  路  152Comments

egoroof picture egoroof  路  90Comments

benjamingr picture benjamingr  路  135Comments

silverwind picture silverwind  路  113Comments