UNPKG

easy-cipher-mate

Version:

A CLI and programmatic tool for encryption/decryption supporting AES-GCM and ChaCha20-Poly1305 algorithms, with text encoding options and line-by-line text file processing.

117 lines (116 loc) 5.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AESGCMEncryptionConfig = exports.AESGCMEncryption = void 0; const encodingUtils_1 = require("../utils/encodingUtils"); /** * AES-GCM encryption implementation with automatic salt and IV generation. * * @remarks * This class provides secure AES-GCM encryption with the following security features: * - Automatic random salt generation (16 bytes) for each encryption * - Automatic random IV generation (12 bytes) for each encryption * - PBKDF2 key derivation with 100,000 iterations * - Authenticated encryption with built-in integrity protection * - Secure data format: [salt | iv | ciphertext] * * @example * ```typescript * const encryption = new AESGCMEncryption(); * const config = new AESGCMEncryptionConfig('my-password'); * * const encrypted = await encryption.encryptText('Hello World', config); * const decrypted = await encryption.decryptText(encrypted.data, config); * ``` */ class AESGCMEncryption { /** * Encrypts a plaintext string using AES-GCM with automatic salt and IV generation. * * @param plaintext - The string to encrypt * @param configuration - The encryption configuration containing password and encoding * @param encoding - Optional text encoding override * @returns Promise resolving to encrypted data in format: [salt | iv | ciphertext] * * @remarks * Each call generates new random salt and IV, ensuring unique ciphertext even for identical plaintext. * The output format is: 16-byte salt + 12-byte IV + AES-GCM ciphertext (includes auth tag). */ async encryptText(plaintext, configuration, encoding) { const { password, textEncoding = 'utf-8' } = configuration; // Generate random salt and IV for each encryption operation const salt = crypto.getRandomValues(new Uint8Array(16)); const iv = crypto.getRandomValues(new Uint8Array(12)); const key = await deriveKey(password, salt); const data = (0, encodingUtils_1.encodeText)(plaintext, encoding !== null && encoding !== void 0 ? encoding : textEncoding); const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, data); // Package salt + iv + ciphertext together const saltBuffer = salt.buffer; const ivBuffer = iv.buffer; const result = new ArrayBuffer(saltBuffer.byteLength + ivBuffer.byteLength + ciphertext.byteLength); const resultView = new Uint8Array(result); resultView.set(new Uint8Array(saltBuffer), 0); resultView.set(new Uint8Array(ivBuffer), saltBuffer.byteLength); resultView.set(new Uint8Array(ciphertext), saltBuffer.byteLength + ivBuffer.byteLength); return { data: result, }; } async decryptText(encryptedData, configuration, encoding) { const { password, textEncoding = 'utf-8' } = configuration; // Parse salt + iv + ciphertext from the packaged data const dataView = new Uint8Array(encryptedData); const salt = dataView.slice(0, 16); const iv = dataView.slice(16, 28); const ciphertext = dataView.slice(28); const key = await deriveKey(password, salt); const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext); return (0, encodingUtils_1.decodeText)(decrypted, encoding !== null && encoding !== void 0 ? encoding : textEncoding); } async encryptFile(fileBuffer, configuration) { const { password } = configuration; // Generate random salt and IV for each encryption operation const salt = crypto.getRandomValues(new Uint8Array(16)); const iv = crypto.getRandomValues(new Uint8Array(12)); const key = await deriveKey(password, salt); const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, fileBuffer); // Package salt + iv + ciphertext together const saltBuffer = salt.buffer; const ivBuffer = iv.buffer; const result = new ArrayBuffer(saltBuffer.byteLength + ivBuffer.byteLength + ciphertext.byteLength); const resultView = new Uint8Array(result); resultView.set(new Uint8Array(saltBuffer), 0); resultView.set(new Uint8Array(ivBuffer), saltBuffer.byteLength); resultView.set(new Uint8Array(ciphertext), saltBuffer.byteLength + ivBuffer.byteLength); return { data: result, }; } async decryptFile(encryptedBuffer, configuration) { const { password } = configuration; // Parse salt + iv + ciphertext from the packaged data const dataView = new Uint8Array(encryptedBuffer); const salt = dataView.slice(0, 16); const iv = dataView.slice(16, 28); const ciphertext = dataView.slice(28); const key = await deriveKey(password, salt); return await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext); } } exports.AESGCMEncryption = AESGCMEncryption; class AESGCMEncryptionConfig { constructor(password, textEncoding) { this.password = password; this.textEncoding = textEncoding !== null && textEncoding !== void 0 ? textEncoding : 'utf-8'; } } exports.AESGCMEncryptionConfig = AESGCMEncryptionConfig; async function deriveKey(password, salt) { const encoder = new TextEncoder(); const keyMaterial = await crypto.subtle.importKey("raw", encoder.encode(password), "PBKDF2", false, ["deriveKey"]); return crypto.subtle.deriveKey({ name: "PBKDF2", salt, iterations: 100000, hash: "SHA-256" }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]); }