Invalid key length in crypto.createCipheriv
Asked Answered
P

4

52

I generated a base64-encoded key using this code in NodeJS v8.11.0:

const secret = 'shezhuansauce';
const key = crypto.createHash('sha256').update(String(secret)).digest('base64');
//output is REtgV24bDB7xQYoMuypiBASMEaJbc59nJWChoXbbmsA=

Using the key, I try to encrypt a string:

var tobeEncrypted = 'some secret string';
const iv = crypto.randomBytes(16).toString('hex').slice(0, 16);
const cipher = crypto.createCipheriv('aes-256-ctr', key, iv);
const encrypted = cipher.update(String(tobeEncrypted), 'utf8', 'hex') + cipher.final('hex');
console.log(encrypted);

However, I received an error:

crypto.js:219
this._handle.initiv(cipher, toBuf(key), toBuf(iv));
           ^
Error: Invalid key length

The key needs to be base64 string as I will store it in a Cloud service and it only receives base64 string.

Any help is appreciated.

Pigskin answered 21/6, 2018 at 7:50 Comment(1)
How I can decrypt in your process?Harri
N
19

You said you stored a key in BASE 64 and the key is 256 bits (or 32 bytes) (which we see that you computed sha256), so simply get that base64 key, then you can get the bytes easily like this:

const key_in_bytes = Buffer.from(BASE_64_KEY, 'base64')

And you can use this key in bytes as your key as:

const cipher = crypto.createCipheriv('aes-256-ctr', key_in_bytes, iv);
Nippur answered 7/11, 2019 at 9:7 Comment(3)
Only answer that doesn't truncate the hash of the secret for no good reason and is extensible to other encoding schemes, e.g. hex, utf8, latin1, ascii, not just base64. Technically, the encoding to base64 can be skipped by using .digest() which will give the Buffer directly.Defamatory
Although the accepted answer is valid, I prefer this approach better for the reasons mentioned aboveAttractive
What about the iv? Do the same buffer from base64 also?Candide
S
66

Just add a tip: Key length is dependent on the algorithm, such as for aes192, it's 24 bytes, or aes256, it's 32 bytes. You need to have a key length of 32 byte (256 bit). So if you change your key line to:

let key = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 32);

it will work.

Steelhead answered 21/6, 2018 at 8:1 Comment(0)
N
19

You said you stored a key in BASE 64 and the key is 256 bits (or 32 bytes) (which we see that you computed sha256), so simply get that base64 key, then you can get the bytes easily like this:

const key_in_bytes = Buffer.from(BASE_64_KEY, 'base64')

And you can use this key in bytes as your key as:

const cipher = crypto.createCipheriv('aes-256-ctr', key_in_bytes, iv);
Nippur answered 7/11, 2019 at 9:7 Comment(3)
Only answer that doesn't truncate the hash of the secret for no good reason and is extensible to other encoding schemes, e.g. hex, utf8, latin1, ascii, not just base64. Technically, the encoding to base64 can be skipped by using .digest() which will give the Buffer directly.Defamatory
Although the accepted answer is valid, I prefer this approach better for the reasons mentioned aboveAttractive
What about the iv? Do the same buffer from base64 also?Candide
Q
5

an alternative approach which may be better than chopping the base 64 string into the first 32 bytes is to simply return the value of the key prior to the digest() call:

let key = crypto.createHash('sha256').update(String(secret))

If the key is cut to 32 bytes after converting it into base 64, that chopped string is an invalid base64 string.

Quechuan answered 22/8, 2019 at 10:27 Comment(0)
V
0

If you use crypto.generateKey you can specify the bit length. If you need to store the key .export to JWK format which you can hand to .createCipheriv.

JWKs make use of the base64url encoding as defined in RFC 4648 [RFC4648]. JWK RFC

function keyGen () {
  return new Promise(function(resolve, reject) {
    generateKey('aes', { length: 256 }, (err, key) => {
      if (err) {
        reject (err);
      }
      
      let jwk = key.export({format:'jwk'});
      resolve (jwk);
    });
  });
}
Vedetta answered 7/8, 2023 at 23:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.