From a987241120e697653f2eb058f801463386db1287 Mon Sep 17 00:00:00 2001 From: ramvignesh-b Date: Wed, 29 Apr 2026 03:11:04 +0530 Subject: [PATCH] refactor: update crypto to generate iv on demand --- frontend/src/utils/crypto.ts | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/frontend/src/utils/crypto.ts b/frontend/src/utils/crypto.ts index 29bffc5..79223c1 100644 --- a/frontend/src/utils/crypto.ts +++ b/frontend/src/utils/crypto.ts @@ -1,7 +1,3 @@ -/** - * 0 knowledge cryptography. No Server involved in encryption/decryption - */ - export interface EncryptedLetter { encrypted_content: string; encrypted_dek: string; @@ -30,9 +26,6 @@ export class CryptoUtils { private static readonly PBKDF2_ITERATIONS = 100_000; private static readonly AES_GCM = { name: "AES-GCM", length: 256 }; - private readonly contentIV = crypto.getRandomValues(new Uint8Array(12)); - private readonly dekIV = crypto.getRandomValues(new Uint8Array(12)); - // Generates a fresh Data Encryption Key (DEK) async initialize() { this.dek = await crypto.subtle.generateKey(CryptoUtils.AES_GCM, true, [ @@ -69,7 +62,6 @@ export class CryptoUtils { /** * Derives a Key Bundle (MasterKey + AuthHash) from a password + email. - * Absolute zero knowledge!! */ public static async deriveKeyBundle( password: string, @@ -118,16 +110,16 @@ export class CryptoUtils { return { masterKey, authHash }; } - // Internal helper to encrypt data and wrap the key private async sealEnvelope( input: Uint8Array, masterKey: CryptoKey, ): Promise { const plainBytes = new Uint8Array(input); + const contentIV = crypto.getRandomValues(new Uint8Array(12)); + const dekIV = crypto.getRandomValues(new Uint8Array(12)); - // encrypt the content with the DEK const ciphertext = await crypto.subtle.encrypt( - { name: "AES-GCM", iv: this.contentIV }, + { name: "AES-GCM", iv: contentIV }, this.dek, plainBytes, ); @@ -135,20 +127,20 @@ export class CryptoUtils { // wrap the DEK with the Master Key (for self/owner access) const wrappedDek = await crypto.subtle.wrapKey("raw", this.dek, masterKey, { name: "AES-GCM", - iv: this.dekIV, + iv: dekIV, }); // export raw DEK for the share URL (recipient access, no master key needed) const rawDek = await crypto.subtle.exportKey("raw", this.dek); return { - encryptedContent: this.packWithIv(this.contentIV, ciphertext), - encrypted_dek: this.packWithIv(this.dekIV, wrappedDek), + encryptedContent: this.packWithIv(contentIV, ciphertext), + encrypted_dek: this.packWithIv(dekIV, wrappedDek), sharingKey: this.toBase64(new Uint8Array(rawDek)), }; } - // Internal helper to unwrap the key and decrypt data + // Unwrap the DEK with the master key to get the key back. Decrypt the content with the DEK. private async openEnvelope( encryptedContent: string, encrypted_dek: string,