All files / libs/kernel/crypto/src/lib crypto.ts

100% Statements 38/38
100% Branches 3/3
100% Functions 3/3
100% Lines 38/38

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 391x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x  
import crypto from 'node:crypto';
 
export interface EncryptedPayload {
  iv: string;
  ciphertext: string;
  tag: string;
}
 
const ALGORITHM = 'aes-256-gcm';
 
// Adapted from https://medium.com/@tony.infisical/guide-to-nodes-crypto-module-for-encryption-decryption-65c077176980
 
export const encryptSymmetric = <T extends object>(key: string, content: T): EncryptedPayload => {
  const plaintext = JSON.stringify({ value: content });
 
  const iv = crypto.randomBytes(12).toString('base64');
  const cipher = crypto.createCipheriv(ALGORITHM, Buffer.from(key, 'base64'), Buffer.from(iv, 'base64'));
  let ciphertext = cipher.update(plaintext, 'utf8', 'base64');
  ciphertext += cipher.final('base64');
  const tag = cipher.getAuthTag().toString('base64');
 
  return { ciphertext, tag, iv };
};
 
export const decryptSymmetric = <T>(key: string, encrypted: EncryptedPayload) => {
  const { ciphertext, tag, iv } = encrypted;
 
  const decipher = crypto.createDecipheriv(ALGORITHM, Buffer.from(key, 'base64'), Buffer.from(iv, 'base64'));
 
  decipher.setAuthTag(Buffer.from(tag, 'base64'));
 
  let plaintext = decipher.update(ciphertext, 'base64', 'utf8');
  plaintext += decipher.final('utf8');
 
  return (JSON.parse(plaintext) as { value: T }).value;
};
 
export const generateEncryptionKey = () => crypto.randomBytes(32).toString('base64');