refactor: update crypto to generate iv on demand

This commit is contained in:
ramvignesh-b
2026-04-29 03:11:04 +05:30
parent ebf7186b06
commit a987241120
+7 -15
View File
@@ -1,7 +1,3 @@
/**
* 0 knowledge cryptography. No Server involved in encryption/decryption
*/
export interface EncryptedLetter { export interface EncryptedLetter {
encrypted_content: string; encrypted_content: string;
encrypted_dek: string; encrypted_dek: string;
@@ -30,9 +26,6 @@ export class CryptoUtils {
private static readonly PBKDF2_ITERATIONS = 100_000; private static readonly PBKDF2_ITERATIONS = 100_000;
private static readonly AES_GCM = { name: "AES-GCM", length: 256 }; 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) // Generates a fresh Data Encryption Key (DEK)
async initialize() { async initialize() {
this.dek = await crypto.subtle.generateKey(CryptoUtils.AES_GCM, true, [ 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. * Derives a Key Bundle (MasterKey + AuthHash) from a password + email.
* Absolute zero knowledge!!
*/ */
public static async deriveKeyBundle( public static async deriveKeyBundle(
password: string, password: string,
@@ -118,16 +110,16 @@ export class CryptoUtils {
return { masterKey, authHash }; return { masterKey, authHash };
} }
// Internal helper to encrypt data and wrap the key
private async sealEnvelope( private async sealEnvelope(
input: Uint8Array, input: Uint8Array,
masterKey: CryptoKey, masterKey: CryptoKey,
): Promise<SealedEnvelope> { ): Promise<SealedEnvelope> {
const plainBytes = new Uint8Array(input); 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( const ciphertext = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv: this.contentIV }, { name: "AES-GCM", iv: contentIV },
this.dek, this.dek,
plainBytes, plainBytes,
); );
@@ -135,20 +127,20 @@ export class CryptoUtils {
// wrap the DEK with the Master Key (for self/owner access) // wrap the DEK with the Master Key (for self/owner access)
const wrappedDek = await crypto.subtle.wrapKey("raw", this.dek, masterKey, { const wrappedDek = await crypto.subtle.wrapKey("raw", this.dek, masterKey, {
name: "AES-GCM", name: "AES-GCM",
iv: this.dekIV, iv: dekIV,
}); });
// export raw DEK for the share URL (recipient access, no master key needed) // export raw DEK for the share URL (recipient access, no master key needed)
const rawDek = await crypto.subtle.exportKey("raw", this.dek); const rawDek = await crypto.subtle.exportKey("raw", this.dek);
return { return {
encryptedContent: this.packWithIv(this.contentIV, ciphertext), encryptedContent: this.packWithIv(contentIV, ciphertext),
encrypted_dek: this.packWithIv(this.dekIV, wrappedDek), encrypted_dek: this.packWithIv(dekIV, wrappedDek),
sharingKey: this.toBase64(new Uint8Array(rawDek)), 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( private async openEnvelope(
encryptedContent: string, encryptedContent: string,
encrypted_dek: string, encrypted_dek: string,