1

So I have an endpoint where I have to decrypt a key, and based on the information I would return some data or not. The problem is that I always get this error:

TypeError: Invalid initialization vector
    at Decipheriv.createCipherBase (node:internal/crypto/cipher:116:19)
    at Decipheriv.createCipherWithIV (node:internal/crypto/cipher:135:3)
    at new Decipheriv (node:internal/crypto/cipher:289:3)
    at createDecipheriv (node:crypto:146:10)

Here is my function to decrypt. The Salt and the IV were concatenated in the begining of the cipher.

import {
  createDecipheriv,
  pbkdf2Sync,
  randomBytes,
  createCipheriv,
} from 'crypto';

const keySize = 256;
const derivationIterations = 1000;

decrypt(cipherText: string, passPhrase: string): string {
    // Get the complete stream of bytes that represent:
    // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
    const cipherTextBytesWithSaltAndIv = Buffer.from(cipherText, 'base64');

    // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
    const saltStringBytes = cipherTextBytesWithSaltAndIv.slice(
      0,
      this.keySize / 8,
    );

    // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
    const ivStringBytes = cipherTextBytesWithSaltAndIv.slice(
      this.keySize / 8,
      (this.keySize / 8) * 2,
    );

    // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
    const cipherTextBytes = cipherTextBytesWithSaltAndIv.slice(
      (this.keySize / 8) * 2,
    );

    const keyBytes = pbkdf2Sync(
      passPhrase,
      saltStringBytes,
      this.derivationIterations,
      this.keySize / 8,
      'sha1',
    );

    const decipher = createDecipheriv('aes-256-cbc', keyBytes, ivStringBytes);
    const plainTextBytes = Buffer.concat([
      decipher.update(cipherTextBytes),
      decipher.final(),
    ]);

    return plainTextBytes.toString('utf8');
  }

I've tried to create a encryption method, because a thought that I would understand the problem better, but I'm getting the same error

encrypt(plainText: string, passPhrase: string) {
    // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
    // so that the same Salt and IV values can be used when decrypting.
    const saltStringBytes = randomBytes(this.keySize / 8);
    const ivStringBytes = randomBytes(this.keySize / 8).toString('hex');
    const plainTextBytes = Buffer.from(plainText, 'utf8');

    const password = pbkdf2Sync(
      passPhrase,
      saltStringBytes,
      this.derivationIterations,
      this.keySize / 8,
      'sha1',
    );

    const cipher = createCipheriv('aes-256-cbc', password, ivStringBytes);

    const encrypted = Buffer.concat([
      saltStringBytes,
      Buffer.from(ivStringBytes, 'hex'),
      cipher.update(plainTextBytes),
      cipher.final(),
    ]);

    return encrypted.toString('base64');
  }

I actually "translated" this code from a C# one, that uses Rfc2898DeriveBytes and RijndaelManaged.

UPDATE

I've discovered that the C# code was taken from this post

What am I missing?

Vangolax
  • 11
  • 4
  • 2
    Your IV has a length of 32 bytes, which causes the error. The IV must match the block size, which for AES is 16 bytes. There may be other issues. An analysis would be easier if you could provide sample (i.e. non-productive) data for `cipherText` and `passPhrase`. – Topaco Mar 01 '23 at 20:46
  • *...I actually "translated" this code from a C# one...* If you have an encryption code, you should post it, even if it is in C#. – Topaco Mar 01 '23 at 20:57
  • 2
    The use of `RijndaelManaged` and a 32 bytes IV could point to Rijndael with a block size of 32 bytes. This would then not be AES and on the NodeJS side a different library would have to be used. But to check this reliably the original C# code is needed. – Topaco Mar 01 '23 at 21:04
  • I've actually discovered that C# code was taken from this post https://stackoverflow.com/a/10177020/10031985 – Vangolax Mar 02 '23 at 02:36
  • The C# code does *not* use AES, but Rijndael with a block size of 256 bits (32 bytes): `symmetricKey.BlockSize = 256`. Note that AES is a subset of Rijndael with a block size of 128 bits (and the three key sizes 128, 192 and 256 bits), s. [here](https://stackoverflow.com/a/748645/9014097). NodeJS's crypto module only supports AES, i.e. you need another NodeJS library. – Topaco Mar 02 '23 at 07:35

0 Answers0