2

I'm getting the error below by running the following code.

Error: Unsupported state or unable to authenticate data at Decipheriv.final (node:internal/crypto/cipher:196:29) at decrypt (/Users/username/dev/playground/node/src/index.ts:14:65)

import crypto from "crypto";

const key = "13312156329479471107309870982123";

const encrypt = (message: string): string => {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
  return `${cipher.update(message, "utf-8", "hex")}${cipher.final("hex")}`;
};

const decrypt = (message: string): string => {
  const iv = crypto.randomBytes(16);
  const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
  return `${decipher.update(message, "hex", "utf-8")}${decipher.final(
    "utf-8"
  )}`;
};

console.log(decrypt(encrypt("hello")));

I've read these posts

but I don't think that I'm getting the same error for the same reason. Any help would be appreciated. Thanks

Chris Krogh
  • 184
  • 4
  • 16

2 Answers2

0

iv needed to be common for both cipher and decipher. Should have read the docs

const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);

const encrypt = (message: string): string => {
  const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
  return `${cipher.update(message, "utf-8", "hex")}${cipher.final("hex")}`;
};

const decrypt = (message: string): string => {
  const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
  return `${decipher.update(message, "hex", "utf-8")}${decipher.final(
    "utf-8"
  )}`;
};
Chris Krogh
  • 184
  • 4
  • 16
0

For me I was using gcm as well; I'm not sure it has anything to do with this.

Ultimately, what ended up working for me was getAuthTag and setAuthTag.

I needed to store mine as a simple string so there's a lot of transitioning to and from hex. Since this is going into a database I also have to store the iv and now the authTag, so I just use | to separate the sections.

Example

import * as crypto from 'crypto'

const key = crypto
  .createHash('sha256')
  .update(String(process.env.ENCRYPTION_KEY))
  .digest('base64')
  .substring(0, 32)
const cipherAlgorithm = 'aes-256-gcm'

export class PropertiesEncryption {
  static encrypt(str: string): string {
    const initVector = crypto.randomBytes(16)
    const initVectorHex = initVector.toString('hex')
    const cipher = crypto.createCipheriv(cipherAlgorithm, key, initVector)
    const encoded = cipher.update(str, 'utf-8', 'hex') + cipher.final('hex')
    const authTag = cipher.getAuthTag().toString('hex')
    const metaAndEncoded = [authTag, initVectorHex, encoded].join('|')

    return metaAndEncoded
  }

  static decrypt(str: string): string {
    const [authTag, initVectorHex, encrypted] = str.split('|')
    const initVector = Buffer.from(initVectorHex, 'hex')
    const decipher = crypto.createDecipheriv(cipherAlgorithm, key, initVector)
    decipher.setAuthTag(Buffer.from(authTag, 'hex'))
    const decrypted =
      decipher.update(encrypted, 'hex', 'utf-8') + decipher.final('utf-8')

    return decrypted
  }
}
CTS_AE
  • 12,987
  • 8
  • 62
  • 63