UNPKG

tumba

Version:

Encrypt and Decrypt files using AES-GCM 256 with PBKDF2 derived keys

89 lines (68 loc) 2.35 kB
import { webcrypto } from 'crypto'; import { Buffer } from 'node:buffer'; const aes = { async secretKey(password, salt, iterations) { // Convert the password to a buffer const encodedPassword = new TextEncoder().encode(password); const algorithm = { name: 'PBKDF2', hash: 'SHA-256', salt: salt, iterations: iterations, }; // Import the key from a raw binary buffer const key = await webcrypto.subtle.importKey( 'raw', encodedPassword, algorithm.name, false, ['deriveKey'], ); const derivedAlgo = { name: 'AES-GCM', length: 256 }; // Derive a key using the PBKDF2 algorithm and a specified number of iterations const keyResult = await webcrypto.subtle.deriveKey( algorithm, key, derivedAlgo, false, ['encrypt', 'decrypt'], ); return keyResult; }, async encrypt(plaintext, password, salt, iterations) { // Generate a random iv const ivUint8 = webcrypto.getRandomValues(new Uint8Array(12)); const algorithm = { name: 'AES-GCM', iv: ivUint8 }; const key = await this.secretKey(password, salt, iterations); // Encrypt the plaintext using the algorithm and the derived key const ciphertext = await webcrypto.subtle.encrypt( algorithm, key, plaintext, ); // Convert the ciphertext to a buffer const ciphertextToUint8 = new Uint8Array(ciphertext); return { iv: ivUint8, cipher: ciphertextToUint8 }; }, async decrypt(ciphertext, password, salt, iterations) { // Convert the ciphertext to a buffer const ciphertextToBuffer = Buffer.from(ciphertext); // Extract the iv const ivBuffer = ciphertextToBuffer.subarray(0, 12); const ivToUint8 = new Uint8Array(ivBuffer); const algorithm = { name: 'AES-GCM', iv: ivToUint8 }; const key = await this.secretKey(password, salt, iterations); // Extract the ciphertext const ciphertextBuffer = ciphertextToBuffer.subarray(12); const ciphertextToUint8 = new Uint8Array(ciphertextBuffer); // Decrypt the ciphertext using the derived key const plaintext = await webcrypto.subtle.decrypt( algorithm, key, ciphertextToUint8, ); const plaintextToBuffer = Buffer.from(plaintext); return plaintextToBuffer; }, }; export default aes;