Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 70 additions & 1 deletion src/email-crypto/core.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,79 @@
import { HybridEncKey, PwdProtectedKey, PublicKeys, PrivateKeys, EmailBody, EmailBodyEncrypted } from '../types';
import {
HybridEncKey,
PwdProtectedKey,
PublicKeys,
PrivateKeys,
EmailBody,
EmailBodyEncrypted,
Email,
EmailPublicParameters,
} from '../types';
import { genSymmetricCryptoKey, encryptSymmetrically, decryptSymmetrically } from '../symmetric-crypto';
import { encapsulateKyber, decapsulateKyber } from '../post-quantum-crypto';
import { deriveWrappingKey, wrapKey, unwrapKey, importWrappingKey } from '../key-wrapper';
import { deriveSecretKey } from '../asymmetric-crypto';
import { getKeyFromPassword, getKeyFromPasswordAndSalt } from '../derive-key';
import { UTF8ToUint8, base64ToUint8Array, uint8ArrayToBase64, uint8ToUTF8, uuidToBytes } from '../utils';
import { getAux } from './utils';

export async function encryptEmailBody(
email: Email,
isSubjectEncrypted: boolean,
): Promise<{
enc: EmailBodyEncrypted;
params: EmailPublicParameters;
encryptionKey: CryptoKey;
}> {
try {
const aux = getAux(email.params, isSubjectEncrypted);

let enc: EmailBodyEncrypted;
let encryptionKey: CryptoKey;
let params = email.params;

if (isSubjectEncrypted) {
const result = await encryptEmailContentAndSubjectSymmetrically(email.body, email.params.subject, aux, email.id);
enc = result.enc;
encryptionKey = result.encryptionKey;
params = { ...email.params, subject: result.encSubject };
} else {
const result = await encryptEmailContentSymmetrically(email.body, aux, email.id);
enc = result.enc;
encryptionKey = result.encryptionKey;
}

return { encryptionKey, enc, params };
} catch (error) {
throw new Error('Failed to encrypt email body', { cause: error });
}
}

export async function decryptEmailBody(
enc: EmailBodyEncrypted,
encParams: EmailPublicParameters,
encryptionKey: CryptoKey,
isSubjectEncrypted: boolean,
): Promise<{
params: EmailPublicParameters;
body: EmailBody;
}> {
try {
const aux = getAux(encParams, isSubjectEncrypted);
let body: EmailBody;
let params = encParams;
if (isSubjectEncrypted) {
const result = await decryptEmailAndSubjectSymmetrically(encryptionKey, aux, encParams.subject, enc);
body = result.body;
params = { ...encParams, subject: result.subject };
} else {
body = await decryptEmailSymmetrically(encryptionKey, aux, enc);
}

return { body, params };
} catch (error) {
throw new Error('Failed to encrypt email body', { cause: error });
}
}

/**
* Symmetrically encrypts an email with a randomly sampled key.
Expand Down
31 changes: 14 additions & 17 deletions src/email-crypto/hybridEncyptedEmail.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
import { PublicKeys, PrivateKeys, HybridEncryptedEmail, Email, UserWithPublicKeys } from '../types';
import {
encryptEmailContentSymmetrically,
decryptEmailSymmetrically,
encryptKeysHybrid,
decryptKeysHybrid,
} from './core';
import { getAux } from './utils';
import { decryptEmailBody, encryptKeysHybrid, decryptKeysHybrid, encryptEmailBody } from './core';

/**
* Encrypts the email using hybrid encryption.
*
* @param email - The email to encrypt.
* @param recipientPublicKeys - The public keys of the recipient.
* @param senderPrivateKey - The private key of the sender.
* @param isSubjectEncrypted - Indicates if the email subject field should be encrypted
* @returns The encrypted email
*/
export async function encryptEmailHybrid(
email: Email,
recipient: UserWithPublicKeys,
senderPrivateKey: PrivateKeys,
isSubjectEncrypted: boolean = false,
): Promise<HybridEncryptedEmail> {
try {
const aux = getAux(email.params);
const { enc, encryptionKey } = await encryptEmailContentSymmetrically(email.body, aux, email.id);
const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted);
const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicKeys, senderPrivateKey);
return { enc, encryptedKey, recipientEmail: recipient.email, params: email.params, id: email.id };
return { enc, encryptedKey, recipientEmail: recipient.email, params, isSubjectEncrypted, id: email.id };
} catch (error) {
throw new Error('Failed to encrypt email with hybrid encryption', { cause: error });
}
Expand All @@ -36,16 +31,17 @@ export async function encryptEmailHybrid(
* @param email - The email to encrypt.
* @param recipients - The recipients with corresponding public keys.
* @param senderPrivateKey - The private key of the sender.
* @param isSubjectEncrypted - Indicates if the email subject field should be encrypted
* @returns The set of encrypted email
*/
export async function encryptEmailHybridForMultipleRecipients(
email: Email,
recipients: UserWithPublicKeys[],
senderPrivateKey: PrivateKeys,
isSubjectEncrypted: boolean = false,
): Promise<HybridEncryptedEmail[]> {
try {
const aux = getAux(email.params);
const { enc, encryptionKey } = await encryptEmailContentSymmetrically(email.body, aux, email.id);
const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted);

const encryptedEmails: HybridEncryptedEmail[] = [];
for (const recipient of recipients) {
Expand All @@ -54,7 +50,8 @@ export async function encryptEmailHybridForMultipleRecipients(
enc,
encryptedKey,
recipientEmail: recipient.email,
params: email.params,
params,
isSubjectEncrypted,
id: email.id,
});
}
Expand All @@ -78,10 +75,10 @@ export async function decryptEmailHybrid(
recipientPrivateKeys: PrivateKeys,
): Promise<Email> {
try {
const aux = getAux(encryptedEmail.params);
const encryptionKey = await decryptKeysHybrid(encryptedEmail.encryptedKey, senderPublicKeys, recipientPrivateKeys);
const body = await decryptEmailSymmetrically(encryptionKey, aux, encryptedEmail.enc);
return { body, params: encryptedEmail.params, id: encryptedEmail.id };
const { isSubjectEncrypted, params: encParams, enc, encryptedKey, id } = encryptedEmail;
const encryptionKey = await decryptKeysHybrid(encryptedKey, senderPublicKeys, recipientPrivateKeys);
const { body, params } = await decryptEmailBody(enc, encParams, encryptionKey, isSubjectEncrypted);
return { body, params, id };
} catch (error) {
throw new Error('Failed to decrypt email with hybrid encryption', { cause: error });
}
Expand Down
102 changes: 0 additions & 102 deletions src/email-crypto/hybridEncyptedEmailAndSubject.ts

This file was deleted.

2 changes: 0 additions & 2 deletions src/email-crypto/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
export * from './hybridEncyptedEmail';
export * from './hybridEncyptedEmailAndSubject';
export * from './pwdProtectedEmail';
export * from './pwdProtectedEmailAndSubject';
export * from './converters';
export * from './emailKeys';
export * from './utils';
29 changes: 14 additions & 15 deletions src/email-crypto/pwdProtectedEmail.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import { PwdProtectedEmail, Email } from '../types';
import {
encryptEmailContentSymmetrically,
decryptEmailSymmetrically,
passwordProtectKey,
removePasswordProtection,
} from './core';
import { getAux } from './utils';
import { decryptEmailBody, passwordProtectKey, removePasswordProtection, encryptEmailBody } from './core';

/**
* Creates a password-protected email.
*
* @param email - The email to password-protect
* @param password - The secret password shared among recipients.
* @param password - The secret password shared among recipients
* @param isSubjectEncrypted - Indicates if the email subject field should be encrypted
* @returns The password-protected email
*/
export async function createPwdProtectedEmail(email: Email, password: string): Promise<PwdProtectedEmail> {
export async function createPwdProtectedEmail(
email: Email,
password: string,
isSubjectEncrypted: boolean = false,
): Promise<PwdProtectedEmail> {
try {
if (!email?.body || !email.params) {
throw new Error('Failed to password-protect email: Invalid email structure');
}
const aux = getAux(email.params);
const { enc, encryptionKey } = await encryptEmailContentSymmetrically(email.body, aux, email.id);
const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted);
const encryptedKey = await passwordProtectKey(encryptionKey, password);
return { enc, encryptedKey, params: email.params, id: email.id };

return { enc, encryptedKey, params, id: email.id, isSubjectEncrypted };
} catch (error) {
throw new Error('Failed to password-protect email', { cause: error });
}
Expand All @@ -37,10 +36,10 @@ export async function createPwdProtectedEmail(email: Email, password: string): P
*/
export async function decryptPwdProtectedEmail(encryptedEmail: PwdProtectedEmail, password: string): Promise<Email> {
try {
const aux = getAux(encryptedEmail.params);
const { isSubjectEncrypted, params: encParams, enc, id } = encryptedEmail;
const encryptionKey = await removePasswordProtection(encryptedEmail.encryptedKey, password);
const body = await decryptEmailSymmetrically(encryptionKey, aux, encryptedEmail.enc);
return { body, params: encryptedEmail.params, id: encryptedEmail.id };
const { body, params } = await decryptEmailBody(enc, encParams, encryptionKey, isSubjectEncrypted);
return { body, params, id };
} catch (error) {
throw new Error('Failed to decrypt password-protect email', { cause: error });
}
Expand Down
62 changes: 0 additions & 62 deletions src/email-crypto/pwdProtectedEmailAndSubject.ts

This file was deleted.

Loading