All files crypto.ts

100% Statements 16/16
100% Branches 1/1
100% Functions 2/2
100% Lines 15/15

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 39 40 41 42 43        4x                 4x 4x   4x   4x 4x                 4x 7x 7x   5x 5x   3x 3x 3x   2x      
/**
 * Utility functions for AES encryption and HMAC integrity using crypto-js.
 * Note: The secret key should be managed securely and not hardcoded in production.
 */
import CryptoJS from 'crypto-js';
 
/**
 * Encrypts and signs data using AES and HMAC.
 * @template T
 * @param {T} data - The data to encrypt.
 * @param {string} secret - The secret key.
 * @returns {string} The encrypted and signed payload (JSON string).
 */
export function encryptAndSign<T>(data: T, secret: string): string {
  const plaintext = JSON.stringify(data);
  // Encrypt with AES
  const ciphertext = CryptoJS.AES.encrypt(plaintext, secret).toString();
  // HMAC for integrity
  const hmac = CryptoJS.HmacSHA256(ciphertext, secret).toString(CryptoJS.enc.Base64);
  return JSON.stringify({ ciphertext, hmac });
}
 
/**
 * Verifies and decrypts data using AES and HMAC.
 * @param {string} payload - The encrypted payload (JSON string).
 * @param {string} secret - The secret key.
 * @returns {object|null} The decrypted object or null if verification fails.
 */
export function verifyAndDecrypt(payload: string, secret: string): object | null {
  try {
    const { ciphertext, hmac } = JSON.parse(payload);
    // Verify HMAC
    const expectedHmac = CryptoJS.HmacSHA256(ciphertext, secret).toString(CryptoJS.enc.Base64);
    if (hmac !== expectedHmac) return null;
    // Decrypt
    const bytes = CryptoJS.AES.decrypt(ciphertext, secret);
    const decrypted = bytes.toString(CryptoJS.enc.Utf8);
    return JSON.parse(decrypted);
  } catch {
    return null;
  }
}