diff --git a/README.md b/README.md index a4df8f0..f7476e2 100644 --- a/README.md +++ b/README.md @@ -119,18 +119,11 @@ const emailBody: EmailBody = { createdAt: '2025-06-14T08:11:22.000Z', labels: ['label 1', 'label2'], }; - -const userAlice = { - email: 'alice email', - name: 'alice', -}; - const userBob = { email: 'bob email', name: 'bob', }; -const { privateKeys: alicePrivateKeys, publicKeys: alicePublicKeys } = await emailCrypto.generateEmailKeys(); -const { privateKeys: bobPrivateKeys, publicKeys: bobPublicKeys } = await emailCrypto.generateEmailKeys(); +const { secretKey: bobPrivateKeys, publicKey: bobPublicKeys } = await generateEmailKeys(); const emailBody: EmailBody = { text: 'email body', @@ -150,8 +143,8 @@ const email: Email = { params: emailParams, body: emailBody, }; -const encryptedEmail = await emailCrypto.encryptEmailHybrid(email, bobPublicKeys, alicePrivateKeys); -const decryptedEmail = await emailCrypto.decryptEmailHybrid(encryptedEmail, alicePublicKeys, bobPrivateKeys); +const encryptedEmail = await emailCrypto.encryptEmailHybrid(email, bobPublicKeys); +const decryptedEmail = await emailCrypto.decryptEmailHybrid(encryptedEmail, bobPrivateKeys); expect(decryptedEmail).toStrictEqual(email); diff --git a/src/email-crypto/converters.ts b/src/email-crypto/converters.ts index 2815ba8..6823252 100644 --- a/src/email-crypto/converters.ts +++ b/src/email-crypto/converters.ts @@ -2,6 +2,12 @@ import { UTF8ToUint8 } from '../utils'; import { User, Email } from '../types'; import { concatBytes } from '@noble/hashes/utils.js'; +/** + * Converts a Users into a Uint8Array. + * + * @param user - The user. + * @returns The Uint8Array representation of the user. + */ export function userToBytes(user: User): Uint8Array { try { const json = JSON.stringify(user); @@ -11,6 +17,12 @@ export function userToBytes(user: User): Uint8Array { } } +/** + * Converts an array of Users into a Uint8Array. + * + * @param recipients - The array of Users. + * @returns The Uint8Array representation of the array of Users. + */ export function recipientsToBytes(recipients: User[]): Uint8Array { try { const array = recipients.map((user) => userToBytes(user)); diff --git a/src/email-crypto/core.ts b/src/email-crypto/core.ts index f99500f..b9b13f1 100644 --- a/src/email-crypto/core.ts +++ b/src/email-crypto/core.ts @@ -1,21 +1,18 @@ -import { - HybridEncKey, - PwdProtectedKey, - PublicKeys, - PrivateKeys, - EmailBody, - EmailBodyEncrypted, - Email, - EmailPublicParameters, -} from '../types'; +import { HybridEncKey, PwdProtectedKey, EmailBody, EmailBodyEncrypted, Email, EmailPublicParameters } from '../types'; import { encryptSymmetrically, decryptSymmetrically, genSymmetricKey } from '../symmetric-crypto'; -import { encapsulateKyber, decapsulateKyber } from '../post-quantum-crypto'; -import { deriveWrappingKey, wrapKey, unwrapKey } from '../key-wrapper'; -import { deriveSecretKey } from '../asymmetric-crypto'; +import { encapsulateHybrid, decapsulateHybrid } from '../hybrid-crypto'; +import { wrapKey, unwrapKey } from '../key-wrapper'; import { getKeyFromPassword, getKeyFromPasswordAndSalt } from '../derive-key'; import { UTF8ToUint8, base64ToUint8Array, uint8ArrayToBase64, uint8ToUTF8, uuidToBytes } from '../utils'; import { getAux } from './utils'; +/** + * Symmetrically encrypts email body. + * + * @param email - The email to encrypt. + * @param isSubjectEncrypted - Indicates if the email subject field was encrypted + * @returns The resulting encrypted email body, updated public parameters (with encrypted subject if it was encrypted) and symmetric key used for encryption + */ export async function encryptEmailBody( email: Email, isSubjectEncrypted: boolean, @@ -48,6 +45,15 @@ export async function encryptEmailBody( } } +/** + * Decrypts symmetrically encrypted email body. + * + * @param enc - The email body to decrypt. + * @param encParams - The email paramaters. + * @param encryptionKey - The symmetric key to decrypt the email. + * @param isSubjectEncrypted - Indicates if the email subject field was encrypted + * @returns The resulting decrypted email body and updated public parameters (with decrypted subject if it was encrypted) + */ export async function decryptEmailBody( enc: EmailBodyEncrypted, encParams: EmailPublicParameters, @@ -131,11 +137,13 @@ export async function encryptEmailContentAndSubjectSymmetrically( } /** - * Decrypts symmetrically encrypted email. + * Decrypts symmetrically encrypted email and its subject. * - * @param encryptedEmail - The email to decrypt. - * @param encryptionKey - The symmetric key. - * @returns The decrypted email + * @param encryptionKey - The symmetric key for encryption. + * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. + * @param encSubject - The encrypted email subject. + * @param enc - The encrypted email body. + * @returns The resulting encrypted emailBody */ export async function decryptEmailAndSubjectSymmetrically( encryptionKey: Uint8Array, @@ -157,8 +165,11 @@ export async function decryptEmailAndSubjectSymmetrically( /** * Symmetrically encrypts an email with a randomly sampled key. * - * @param email - The email to encrypt. - * @returns The resulting ciphertext and the used symmetric key + * @param emailBody - The email body to encrypt. + * @param encryptionKey - The symmetric key for encryption. + * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. + * @param emailID - The unique identifier of the email. + * @returns The resulting encrypted emailBody */ export async function encryptEmailContentSymmetricallyWithKey( emailBody: EmailBody, @@ -183,6 +194,15 @@ export async function encryptEmailContentSymmetricallyWithKey( } } +/** + * Symmetrically encrypts email attachements. + * + * @param attachments - The attachments. + * @param encryptionKey - The symmetric key. + * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. + * @param emailID - The unique identifier of the email. + * @returns The decrypted email attackements + */ async function encryptEmailAttachements( attachments: string[], encryptionKey: Uint8Array, @@ -203,6 +223,14 @@ async function encryptEmailAttachements( } } +/** + * Decrypts symmetrically encrypted email attachements. + * + * @param encryptedAttachments - The encrypted attachments. + * @param encryptionKey - The symmetric key. + * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. + * @returns The decrypted email attackements + */ async function decryptEmailAttachements( encryptedAttachments: Uint8Array[], encryptionKey: Uint8Array, @@ -223,8 +251,9 @@ async function decryptEmailAttachements( /** * Decrypts symmetrically encrypted email. * - * @param encryptedEmail - The email to decrypt. * @param encryptionKey - The symmetric key. + * @param aux - The auxiliary data (e.g., email ID or timestamp) for AEAD. + * @param enc - The email body to decrypt. * @returns The decrypted email */ export async function decryptEmailSymmetrically( @@ -253,24 +282,18 @@ export async function decryptEmailSymmetrically( * Encrypts the email symmetric key using hybrid encryption. * * @param emailEncryptionKey - The symmetric key used for email encryption. - * @param recipientPublicKey - The public key of the recipient. - * @param senderPrivateKey - The private key of the sender. + * @param recipientPublicHybridKey - The public key of the recipient. * @returns The encrypted email symmetric key */ export async function encryptKeysHybrid( emailEncryptionKey: Uint8Array, - recipientPublicKey: PublicKeys, - senderPrivateKey: PrivateKeys, + recipientPublicHybridKey: Uint8Array, ): Promise { try { - const eccSecret = await deriveSecretKey(recipientPublicKey.eccPublicKey, senderPrivateKey.eccPrivateKey); - const { cipherText: kyberCiphertext, sharedSecret: kyberSecret } = encapsulateKyber( - recipientPublicKey.kyberPublicKey, - ); - const wrappingKey = await deriveWrappingKey(eccSecret, kyberSecret); - const encryptedKey = await wrapKey(emailEncryptionKey, wrappingKey); + const { cipherText, sharedSecret } = encapsulateHybrid(recipientPublicHybridKey); + const encryptedKey = await wrapKey(emailEncryptionKey, sharedSecret); const encryptedKeyBase64 = uint8ArrayToBase64(encryptedKey); - const kyberCiphertextBase64 = uint8ArrayToBase64(kyberCiphertext); + const kyberCiphertextBase64 = uint8ArrayToBase64(cipherText); return { encryptedKey: encryptedKeyBase64, kyberCiphertext: kyberCiphertextBase64 }; } catch (error) { @@ -282,22 +305,18 @@ export async function encryptKeysHybrid( * Decrypts the email symmetric key encrypted via hybrid encryption. * * @param encryptedKey - The encrypted email key. - * @param senderPublicKey - The public key of the sender. * @param recipientPrivateKey - The private key of the recipient. * @returns The email encryption key */ export async function decryptKeysHybrid( encryptedKey: HybridEncKey, - senderPublicKey: PublicKeys, - recipientPrivateKey: PrivateKeys, + recipientPrivateKey: Uint8Array, ): Promise { try { const kyberCiphertext = base64ToUint8Array(encryptedKey.kyberCiphertext); const encKey = base64ToUint8Array(encryptedKey.encryptedKey); - const eccSecret = await deriveSecretKey(senderPublicKey.eccPublicKey, recipientPrivateKey.eccPrivateKey); - const kyberSecret = decapsulateKyber(kyberCiphertext, recipientPrivateKey.kyberPrivateKey); - const wrappingKey = await deriveWrappingKey(eccSecret, kyberSecret); - const encryptionKey = await unwrapKey(encKey, wrappingKey); + const sharedSecret = decapsulateHybrid(kyberCiphertext, recipientPrivateKey); + const encryptionKey = await unwrapKey(encKey, sharedSecret); return encryptionKey; } catch (error) { throw new Error('Failed to decrypt email key encrypted via hybrid encryption', { cause: error }); diff --git a/src/email-crypto/emailKeys.ts b/src/email-crypto/emailKeys.ts index e11e3bc..9f36d1e 100644 --- a/src/email-crypto/emailKeys.ts +++ b/src/email-crypto/emailKeys.ts @@ -1,30 +1,11 @@ -import { generateEccKeys } from '../asymmetric-crypto'; -import { generateKyberKeys } from '../post-quantum-crypto'; -import { EmailKeys } from '../types'; +import { genHybridKeys } from '../hybrid-crypto'; +import { HybridKeyPair } from '../types'; /** - * Generates public and private keys for email service. + * Generates public and private keys for email encryption. * * @returns The user's private and public keys */ -export async function generateEmailKeys(): Promise { - try { - const kyberKeys = generateKyberKeys(); - const keys = await generateEccKeys(); - - const emailKeys: EmailKeys = { - publicKeys: { - eccPublicKey: keys.publicKey, - kyberPublicKey: kyberKeys.publicKey, - }, - privateKeys: { - eccPrivateKey: keys.privateKey, - kyberPrivateKey: kyberKeys.secretKey, - }, - }; - - return emailKeys; - } catch (error) { - throw new Error('Failed to generate keys for email service', { cause: error }); - } +export async function generateEmailKeys(): Promise { + return genHybridKeys(); } diff --git a/src/email-crypto/hybridEncyptedEmail.ts b/src/email-crypto/hybridEncyptedEmail.ts index e152664..60fd1a4 100644 --- a/src/email-crypto/hybridEncyptedEmail.ts +++ b/src/email-crypto/hybridEncyptedEmail.ts @@ -1,4 +1,4 @@ -import { PublicKeys, PrivateKeys, HybridEncryptedEmail, Email, UserWithPublicKeys } from '../types'; +import { HybridEncryptedEmail, Email, UserWithPublicKey } from '../types'; import { decryptEmailBody, encryptKeysHybrid, decryptKeysHybrid, encryptEmailBody } from './core'; /** @@ -6,19 +6,17 @@ import { decryptEmailBody, encryptKeysHybrid, decryptKeysHybrid, encryptEmailBod * * @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, + recipient: UserWithPublicKey, isSubjectEncrypted: boolean = false, ): Promise { try { const { encryptionKey, params, enc } = await encryptEmailBody(email, isSubjectEncrypted); - const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicKeys, senderPrivateKey); + const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicHybridKey); 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 }); @@ -30,14 +28,12 @@ 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, + recipients: UserWithPublicKey[], isSubjectEncrypted: boolean = false, ): Promise { try { @@ -45,7 +41,7 @@ export async function encryptEmailHybridForMultipleRecipients( const encryptedEmails: HybridEncryptedEmail[] = []; for (const recipient of recipients) { - const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicKeys, senderPrivateKey); + const encryptedKey = await encryptKeysHybrid(encryptionKey, recipient.publicHybridKey); encryptedEmails.push({ enc, encryptedKey, @@ -65,18 +61,16 @@ export async function encryptEmailHybridForMultipleRecipients( * Decrypts the email using hybrid encryption. * * @param encryptedEmail - The encrypted email. - * @param senderPublicKeys - The public key of the sender. - * @param recipientPrivateKeys - The private key of the recipient. + * @param recipientPrivateHybridKeys - The private key of the recipient. * @returns The decrypted email */ export async function decryptEmailHybrid( encryptedEmail: HybridEncryptedEmail, - senderPublicKeys: PublicKeys, - recipientPrivateKeys: PrivateKeys, + recipientPrivateHybridKeys: Uint8Array, ): Promise { try { const { isSubjectEncrypted, params: encParams, enc, encryptedKey, id } = encryptedEmail; - const encryptionKey = await decryptKeysHybrid(encryptedKey, senderPublicKeys, recipientPrivateKeys); + const encryptionKey = await decryptKeysHybrid(encryptedKey, recipientPrivateHybridKeys); const { body, params } = await decryptEmailBody(enc, encParams, encryptionKey, isSubjectEncrypted); return { body, params, id }; } catch (error) { diff --git a/src/index.ts b/src/index.ts index 4b0318e..1da2e3d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -81,8 +81,6 @@ export { uint8ArrayToBase64, base64ToUint8Array, genMnemonic, - base64ToPublicKey, - publicKeyToBase64, generateUuid, uuidToBytes, bytesToUuid, diff --git a/src/keystore-crypto/core.ts b/src/keystore-crypto/core.ts index 60090fd..69707c7 100644 --- a/src/keystore-crypto/core.ts +++ b/src/keystore-crypto/core.ts @@ -1,44 +1,35 @@ import { encryptSymmetrically, decryptSymmetrically } from '../symmetric-crypto'; -import { base64ToUint8Array, uint8ArrayToBase64, UTF8ToUint8, mnemonicToBytes, publicKeyToBase64 } from '../utils'; +import { base64ToUint8Array, uint8ArrayToBase64, UTF8ToUint8, mnemonicToBytes } from '../utils'; import { deriveSymmetricKeyFromContext } from '../derive-key'; import { CONTEXT_ENC_KEYSTORE, AES_KEY_BIT_LENGTH, CONTEXT_RECOVERY } from '../constants'; import { getBytesFromData } from '../hash'; -import { EmailKeys, EncryptedKeystore, KeystoreType } from '../types'; -import { exportPrivateKey, importPrivateKey, importPublicKey } from '../asymmetric-crypto'; +import { EncryptedKeystore, HybridKeyPair, KeystoreType } from '../types'; /** - * Encrypts the keystore content using symmetric encryption + * Encrypts the user's hybrid key using symmetric encryption to get a keystore * * @param secretKey - The symmetric key to encrypt the keystore content - * @param content - The content of the keystore - * @param userID - The ID of the user - * @param tag - The keystore type-specific tag string - * @returns The encrypted keystore content + * @param key - The hybrid key pair + * @param userEmail - The email of the user + * @param type - The keystore type + * @returns The encrypted keystore */ export async function encryptKeystoreContent( secretKey: Uint8Array, - keys: EmailKeys, + keys: HybridKeyPair, userEmail: string, type: KeystoreType, ): Promise { try { const aux = UTF8ToUint8(userEmail + type); - const publicKeys = await publicKeyToBase64(keys.publicKeys); - const kyberPrivateKeyEnc = await encryptSymmetrically(secretKey, keys.privateKeys.kyberPrivateKey, aux); - const eccPrivateKey = await exportPrivateKey(keys.privateKeys.eccPrivateKey); - const eccPrivateKeyEnc = await encryptSymmetrically(secretKey, eccPrivateKey, aux); - const encryptedKeys = { - publicKeys, - privateKeys: { - kyberPrivateKeyBase64: uint8ArrayToBase64(kyberPrivateKeyEnc), - eccPrivateKeyBase64: uint8ArrayToBase64(eccPrivateKeyEnc), - }, - }; + const publicKey = uint8ArrayToBase64(keys.publicKey); + const secretKeyEncrypted = await encryptSymmetrically(secretKey, keys.secretKey, aux); const keystore: EncryptedKeystore = { userEmail, type, - encryptedKeys, + publicKey, + privateKeyEncrypted: uint8ArrayToBase64(secretKeyEncrypted), }; return keystore; } catch (error) { @@ -49,37 +40,23 @@ export async function encryptKeystoreContent( /** * Decrypts the keystore content using symmetric encryption * - * @param secretKey - The symmetric key to decrypt the keystore content + * @param kesytoreOpeningKey - The symmetric key to decrypt the keystore content * @param encryptedKeys - The encrypted keystore content - * @param userEmail - The ID of the user - * @param tag - The keystore type-specific tag string - * @returns The decrypted keystore content + * @returns The decrypted hybrid key pair contained in the keystore */ export async function decryptKeystoreContent( - secretKey: Uint8Array, + kesytoreOpeningKey: Uint8Array, encryptedKeystore: EncryptedKeystore, -): Promise { +): Promise { try { const aux = UTF8ToUint8(encryptedKeystore.userEmail + encryptedKeystore.type); - const kyberPublicKey = base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.kyberPublicKeyBase64); - const eccPublicArray = base64ToUint8Array(encryptedKeystore.encryptedKeys.publicKeys.eccPublicKeyBase64); - const eccPublicKey = await importPublicKey(eccPublicArray); - const encKyberPrivateKey = base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.kyberPrivateKeyBase64); - const kyberPrivateKey = await decryptSymmetrically(secretKey, encKyberPrivateKey, aux); - const eccEncArray = base64ToUint8Array(encryptedKeystore.encryptedKeys.privateKeys.eccPrivateKeyBase64); - const eccKey = await decryptSymmetrically(secretKey, eccEncArray, aux); - const eccPrivateKey = await importPrivateKey(eccKey); - const keys = { - publicKeys: { - kyberPublicKey, - eccPublicKey, - }, - privateKeys: { - kyberPrivateKey, - eccPrivateKey, - }, + const publicKey = base64ToUint8Array(encryptedKeystore.publicKey); + const ciphertext = base64ToUint8Array(encryptedKeystore.privateKeyEncrypted); + const secretKey = await decryptSymmetrically(kesytoreOpeningKey, ciphertext, aux); + return { + publicKey, + secretKey, }; - return keys; } catch (error) { throw new Error('Failed to decrypt keystore content', { cause: error }); } diff --git a/src/keystore-crypto/emailEncryptionKey.ts b/src/keystore-crypto/emailEncryptionKey.ts index c8e847d..a0538f1 100644 --- a/src/keystore-crypto/emailEncryptionKey.ts +++ b/src/keystore-crypto/emailEncryptionKey.ts @@ -1,14 +1,14 @@ -import { EmailKeys, EncryptedKeystore, KeystoreType } from '../types'; +import { EncryptedKeystore, KeystoreType, HybridKeyPair } from '../types'; import { genMnemonic } from '../utils'; import { encryptKeystoreContent, decryptKeystoreContent, deriveEncryptionKeystoreKey, deriveRecoveryKey } from './core'; -import { generateEmailKeys } from '../email-crypto'; +import { genHybridKeys } from '../hybrid-crypto'; /** - * Generates email keys and creates encrypted main and recovery keystores + * Generates hybrid keys and creates encrypted main and recovery keystores * The main keystore encryption key is derived from the base key (stored in session storage) * The recovery keystore encryption key is derived from the recovery codes * - * @returns The encryption and recovery keystores, recovery codes and email keys + * @returns The encryption and recovery keystores, recovery codes and hybrid keys */ export async function createEncryptionAndRecoveryKeystores( userEmail: string, @@ -17,10 +17,10 @@ export async function createEncryptionAndRecoveryKeystores( encryptionKeystore: EncryptedKeystore; recoveryKeystore: EncryptedKeystore; recoveryCodes: string; - keys: EmailKeys; + keys: HybridKeyPair; }> { try { - const keys = await generateEmailKeys(); + const keys = genHybridKeys(); const secretKey = await deriveEncryptionKeystoreKey(baseKey); const encryptionKeystore = await encryptKeystoreContent(secretKey, keys, userEmail, KeystoreType.ENCRYPTION); @@ -46,7 +46,7 @@ export async function createEncryptionAndRecoveryKeystores( export async function openEncryptionKeystore( encryptedKeystore: EncryptedKeystore, baseKey: Uint8Array, -): Promise { +): Promise { try { if (encryptedKeystore.type != KeystoreType.ENCRYPTION) { throw new Error('Input is invalid'); @@ -70,7 +70,7 @@ export async function openEncryptionKeystore( export async function openRecoveryKeystore( recoveryCodes: string, encryptedKeystore: EncryptedKeystore, -): Promise { +): Promise { try { if (encryptedKeystore.type != KeystoreType.RECOVERY) { throw new Error('Input is invalid'); diff --git a/src/types.ts b/src/types.ts index 4bc0763..efa4b2b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,8 @@ export type EncryptedKeystore = { userEmail: string; type: KeystoreType; - encryptedKeys: EmailKeysEncrypted; + publicKey: string; + privateKeyEncrypted: string; }; export type User = { @@ -9,8 +10,8 @@ export type User = { name: string; }; -export type UserWithPublicKeys = User & { - publicKeys: PublicKeys; +export type UserWithPublicKey = User & { + publicHybridKey: Uint8Array; }; export type PublicKeys = { @@ -28,26 +29,6 @@ export type HybridKeyPair = { secretKey: Uint8Array; }; -export type PrivateKeys = { - eccPrivateKey: CryptoKey; - kyberPrivateKey: Uint8Array; -}; - -export type PrivateKeysEncrypted = { - eccPrivateKeyBase64: string; - kyberPrivateKeyBase64: string; -}; - -export type EmailKeys = { - publicKeys: PublicKeys; - privateKeys: PrivateKeys; -}; - -export type EmailKeysEncrypted = { - publicKeys: PublicKeysBase64; - privateKeys: PrivateKeysEncrypted; -}; - export type HybridEncryptedEmail = { encryptedKey: HybridEncKey; enc: EmailBodyEncrypted; diff --git a/src/utils/index.ts b/src/utils/index.ts index 8fe8d83..488eb76 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,3 @@ export * from './converters'; -export * from './keyConverters'; export * from './genMnemonic'; export * from './genID'; diff --git a/src/utils/keyConverters.ts b/src/utils/keyConverters.ts deleted file mode 100644 index d299e06..0000000 --- a/src/utils/keyConverters.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { uint8ArrayToBase64, base64ToUint8Array } from '.'; -import { PublicKeys, PublicKeysBase64 } from '../types'; -import { exportPublicKey, importPublicKey } from '../asymmetric-crypto'; - -/** - * Converts a base64 string into PublicKeys type. - * - * @param base64 - The base64 representation of the public key. - * @returns The resulting PublicKeys. - */ -export async function base64ToPublicKey(base64: PublicKeysBase64): Promise { - try { - const eccPublicKeyBytes = base64ToUint8Array(base64.eccPublicKeyBase64); - const eccPublicKey = await importPublicKey(eccPublicKeyBytes); - const kyberPublicKey = base64ToUint8Array(base64.kyberPublicKeyBase64); - return { - eccPublicKey: eccPublicKey, - kyberPublicKey: kyberPublicKey, - }; - } catch (error) { - throw new Error('Failed to convert base64 to PublicKeys', { cause: error }); - } -} - -/** - * Converts a PublicKeys type into PublicKeysBase64. - * - * @param key - The PublicKeys key. - * @returns The resulting PublicKeysBase64. - */ -export async function publicKeyToBase64(key: PublicKeys): Promise { - try { - const eccPublicKeyArray = await exportPublicKey(key.eccPublicKey); - const keys = { - eccPublicKeyBase64: uint8ArrayToBase64(eccPublicKeyArray), - kyberPublicKeyBase64: uint8ArrayToBase64(key.kyberPublicKey), - }; - return keys; - } catch (error) { - throw new Error('Failed to convert key of the type PublicKeys to PublicKeysBase64', { cause: error }); - } -} diff --git a/tests/email-crypto/core.test.ts b/tests/email-crypto/core.test.ts index b4a7d23..7e31c14 100644 --- a/tests/email-crypto/core.test.ts +++ b/tests/email-crypto/core.test.ts @@ -8,7 +8,7 @@ import { } from '../../src/email-crypto/core'; import { generateUuid } from '../../src/utils'; import { getAux } from '../../src/email-crypto'; -import { genSymmetricCryptoKey } from '../../src/symmetric-crypto'; +import { genSymmetricKey } from '../../src/symmetric-crypto'; describe('Test email crypto functions', () => { const emailBody: EmailBody = { @@ -53,7 +53,7 @@ describe('Test email crypto functions', () => { it('should throw an error if decryption fails', async () => { const { enc, encryptionKey } = await encryptEmailContentSymmetrically(emailBody, aux, id); - const bad_encryptionKey = await genSymmetricCryptoKey(); + const bad_encryptionKey = await genSymmetricKey(); await expect(decryptEmailSymmetrically(bad_encryptionKey, aux, enc)).rejects.toThrowError( /Failed to symmetrically decrypt email/, ); @@ -64,7 +64,7 @@ describe('Test email crypto functions', () => { ); }); it('should throw an error if decryption fails', async () => { - const bad_encryptionKey = await genSymmetricCryptoKey(); + const bad_encryptionKey = await genSymmetricKey(); const { enc, encryptionKey, encSubject } = await encryptEmailContentAndSubjectSymmetrically( emailBody, emailParams.subject, diff --git a/tests/email-crypto/hybridEmail.test.ts b/tests/email-crypto/hybridEmail.test.ts index d7b141c..364073e 100644 --- a/tests/email-crypto/hybridEmail.test.ts +++ b/tests/email-crypto/hybridEmail.test.ts @@ -6,17 +6,7 @@ import { generateEmailKeys, } from '../../src/email-crypto'; -import { generateKyberKeys } from '../../src/post-quantum-crypto/kyber768'; -import { generateEccKeys } from '../../src/asymmetric-crypto'; -import { - EmailBody, - PublicKeys, - HybridEncryptedEmail, - HybridEncKey, - PrivateKeys, - EmailPublicParameters, - Email, -} from '../../src/types'; +import { EmailBody, HybridEncryptedEmail, HybridEncKey, EmailPublicParameters, Email } from '../../src/types'; import { generateUuid } from '../../src/utils'; describe('Test email crypto functions', async () => { @@ -49,35 +39,44 @@ describe('Test email crypto functions', async () => { params: emailParams, }; - const { privateKeys: alicePrivateKeys, publicKeys: alicePublicKeys } = await generateEmailKeys(); - const { privateKeys: bobPrivateKeys, publicKeys: bobPublicKeys } = await generateEmailKeys(); + const { secretKey: alicePrivateKeys, publicKey: alicePublicKeys } = await generateEmailKeys(); + const { secretKey: bobPrivateKeys, publicKey: bobPublicKeys } = await generateEmailKeys(); const bobWithPublicKeys = { ...userBob, - publicKeys: bobPublicKeys, + publicHybridKey: bobPublicKeys, + }; + const aliceWithPublicKeys = { + ...userAlice, + publicHybridKey: alicePublicKeys, }; it('should encrypt and decrypt email sucessfully', async () => { - const encryptedEmail = await encryptEmailHybrid(email, bobWithPublicKeys, alicePrivateKeys); - const decryptedEmail = await decryptEmailHybrid(encryptedEmail, alicePublicKeys, bobPrivateKeys); + const encryptedEmail = await encryptEmailHybrid(email, bobWithPublicKeys); + const decryptedEmail = await decryptEmailHybrid(encryptedEmail, bobPrivateKeys); expect(decryptedEmail).toStrictEqual(email); }); it('should throw an error if public key is given instead of the secret one', async () => { - const keys = await generateEccKeys(); - const kyberKeys = generateKyberKeys(); - - const bad_alicePrivateKey: PrivateKeys = { - eccPrivateKey: keys.publicKey, - kyberPrivateKey: kyberKeys.secretKey, + const bad_recipient = { + ...userAlice, + publicHybridKey: alicePrivateKeys, }; - await expect(encryptEmailHybrid(email, bobWithPublicKeys, bad_alicePrivateKey)).rejects.toThrowError( + await expect(encryptEmailHybrid(email, bad_recipient)).rejects.toThrowError( /Failed to encrypt email with hybrid encryption/, ); }); + it('should throw an error if not intended recipient', async () => { + const encryptedEmail = await encryptEmailHybrid(email, bobWithPublicKeys); + + await expect(decryptEmailHybrid(encryptedEmail, alicePrivateKeys)).rejects.toThrowError( + /Failed to decrypt email with hybrid encryption/, + ); + }); + it('should throw an error if hybrid email decryption fails', async () => { const encKey: HybridEncKey = { kyberCiphertext: 'mock kyber ciphertext', @@ -94,52 +93,31 @@ describe('Test email crypto functions', async () => { isSubjectEncrypted: false, }; - await expect(decryptEmailHybrid(bad_encrypted_email, alicePublicKeys, bobPrivateKeys)).rejects.toThrowError( + await expect(decryptEmailHybrid(bad_encrypted_email, bobPrivateKeys)).rejects.toThrowError( /Failed to decrypt email with hybrid encryption/, ); }); it('should encrypt email to multiple senders sucessfully', async () => { - const eveKyberKeys = generateKyberKeys(); - const eveKeys = await generateEccKeys(); - - const evePublicKeys: PublicKeys = { - eccPublicKey: eveKeys.publicKey, - kyberPublicKey: eveKyberKeys.publicKey, - }; - - const eveWithPublicKeys = { - email: 'eve email', - name: 'eve', - publicKeys: evePublicKeys, - }; - - const encryptedEmail = await encryptEmailHybridForMultipleRecipients( - email, - [bobWithPublicKeys, eveWithPublicKeys], - alicePrivateKeys, - ); + const encryptedEmail = await encryptEmailHybridForMultipleRecipients(email, [ + bobWithPublicKeys, + aliceWithPublicKeys, + ]); expect(encryptedEmail.length).toBe(2); expect(encryptedEmail[0].enc).toBe(encryptedEmail[1].enc); }); it('should throw an error if encryption to multiple recipients fails', async () => { - const eveKyberKeys = generateKyberKeys(); - const eveKeys = await generateEccKeys(); - - const bad_evePublicKeys: PublicKeys = { - eccPublicKey: eveKeys.privateKey, - kyberPublicKey: eveKyberKeys.publicKey, - }; + const bad_evePublicKeys = new Uint8Array(); const bad_eveWithPublicKeys = { email: 'eve email', name: 'eve', - publicKeys: bad_evePublicKeys, + publicHybridKey: bad_evePublicKeys, }; await expect( - encryptEmailHybridForMultipleRecipients(email, [bobWithPublicKeys, bad_eveWithPublicKeys], alicePrivateKeys), + encryptEmailHybridForMultipleRecipients(email, [bobWithPublicKeys, bad_eveWithPublicKeys]), ).rejects.toThrowError(/Failed to encrypt email to multiple recipients with hybrid encryption/); }); }); diff --git a/tests/email-crypto/hybridEmailAndSubject.test.ts b/tests/email-crypto/hybridEmailAndSubject.test.ts index ac4b447..04e80cc 100644 --- a/tests/email-crypto/hybridEmailAndSubject.test.ts +++ b/tests/email-crypto/hybridEmailAndSubject.test.ts @@ -6,17 +6,7 @@ import { generateEmailKeys, } from '../../src/email-crypto'; -import { generateKyberKeys } from '../../src/post-quantum-crypto/kyber768'; -import { generateEccKeys } from '../../src/asymmetric-crypto'; -import { - EmailBody, - PublicKeys, - HybridEncryptedEmail, - HybridEncKey, - PrivateKeys, - EmailPublicParameters, - Email, -} from '../../src/types'; +import { EmailBody, HybridEncryptedEmail, HybridEncKey, EmailPublicParameters, Email } from '../../src/types'; import { generateUuid } from '../../src/utils'; describe('Test email crypto functions', async () => { @@ -49,36 +39,26 @@ describe('Test email crypto functions', async () => { params: emailParams, }; - const { privateKeys: alicePrivateKeys, publicKeys: alicePublicKeys } = await generateEmailKeys(); - const { privateKeys: bobPrivateKeys, publicKeys: bobPublicKeys } = await generateEmailKeys(); + const { secretKey: alicePrivateKeys, publicKey: alicePublicKeys } = await generateEmailKeys(); + const { secretKey: bobPrivateKeys, publicKey: bobPublicKeys } = await generateEmailKeys(); const bobWithPublicKeys = { ...userBob, - publicKeys: bobPublicKeys, + publicHybridKey: bobPublicKeys, + }; + const aliceWithPublicKeys = { + ...userAlice, + publicHybridKey: alicePublicKeys, }; it('should encrypt and decrypt email sucessfully', async () => { - const encryptedEmail = await encryptEmailHybrid(email, bobWithPublicKeys, alicePrivateKeys, true); - const decryptedEmail = await decryptEmailHybrid(encryptedEmail, alicePublicKeys, bobPrivateKeys); + const encryptedEmail = await encryptEmailHybrid(email, bobWithPublicKeys, true); + const decryptedEmail = await decryptEmailHybrid(encryptedEmail, bobPrivateKeys); expect(decryptedEmail).toStrictEqual(email); expect(encryptedEmail.params.subject).not.toBe(email.params.subject); }); - it('should throw an error if public key is given instead of the secret one', async () => { - const keys = await generateEccKeys(); - const kyberKeys = generateKyberKeys(); - - const bad_alicePrivateKey: PrivateKeys = { - eccPrivateKey: keys.publicKey, - kyberPrivateKey: kyberKeys.secretKey, - }; - - await expect(encryptEmailHybrid(email, bobWithPublicKeys, bad_alicePrivateKey, true)).rejects.toThrowError( - /Failed to encrypt email with hybrid encryption/, - ); - }); - it('should throw an error if hybrid email decryption fails', async () => { const encKey: HybridEncKey = { kyberCiphertext: 'mock kyber ciphertext', @@ -95,25 +75,15 @@ describe('Test email crypto functions', async () => { isSubjectEncrypted: true, }; - await expect(decryptEmailHybrid(bad_encrypted_email, alicePublicKeys, bobPrivateKeys)).rejects.toThrowError( + await expect(decryptEmailHybrid(bad_encrypted_email, bobPrivateKeys)).rejects.toThrowError( /Failed to decrypt email with hybrid encryption/, ); }); it('should encrypt the email to multiple senders sucessfully', async () => { - const { privateKeys: evePrivateKeys, publicKeys: evePublicKeys } = await generateEmailKeys(); - - const eveWithPublicKeys = { - email: 'eve email', - name: 'eve', - id: '3', - publicKeys: evePublicKeys, - }; - const encryptedEmail = await encryptEmailHybridForMultipleRecipients( email, - [bobWithPublicKeys, eveWithPublicKeys], - alicePrivateKeys, + [bobWithPublicKeys, aliceWithPublicKeys], true, ); @@ -122,35 +92,21 @@ describe('Test email crypto functions', async () => { expect(encryptedEmail[0].params.subject).toBe(encryptedEmail[1].params.subject); expect(encryptedEmail[0].params.subject).not.toBe(email.params.subject); - const decEmailBob = await decryptEmailHybrid(encryptedEmail[0], alicePublicKeys, bobPrivateKeys); + const decEmailBob = await decryptEmailHybrid(encryptedEmail[0], bobPrivateKeys); expect(decEmailBob).toStrictEqual(email); - const decEmailEve = await decryptEmailHybrid(encryptedEmail[1], alicePublicKeys, evePrivateKeys); + const decEmailEve = await decryptEmailHybrid(encryptedEmail[1], alicePrivateKeys); expect(decEmailEve).toStrictEqual(email); }); it('should throw an error if encryption to multiple recipients fails', async () => { - const eveKyberKeys = generateKyberKeys(); - const eveKeys = await generateEccKeys(); - - const bad_evePublicKeys: PublicKeys = { - eccPublicKey: eveKeys.privateKey, - kyberPublicKey: eveKyberKeys.publicKey, - }; - const bad_eveWithPublicKeys = { email: 'eve email', name: 'eve', - id: '3', - publicKeys: bad_evePublicKeys, + publicHybridKey: new Uint8Array(), }; await expect( - encryptEmailHybridForMultipleRecipients( - email, - [bobWithPublicKeys, bad_eveWithPublicKeys], - alicePrivateKeys, - true, - ), + encryptEmailHybridForMultipleRecipients(email, [bobWithPublicKeys, bad_eveWithPublicKeys], true), ).rejects.toThrowError(/Failed to encrypt email to multiple recipients with hybrid encryption/); }); }); diff --git a/tests/keystore-crypto/emailEncryptionKeys.test.ts b/tests/keystore-crypto/emailEncryptionKeys.test.ts index e44c436..28e1ba6 100644 --- a/tests/keystore-crypto/emailEncryptionKeys.test.ts +++ b/tests/keystore-crypto/emailEncryptionKeys.test.ts @@ -5,7 +5,7 @@ import { openRecoveryKeystore, } from '../../src/keystore-crypto'; import { genSymmetricKey } from '../../src/symmetric-crypto'; -import { KYBER768_PUBLIC_KEY_LENGTH, KYBER768_SECRET_KEY_LENGTH } from '../../src/constants'; +import { XWING_PUBLIC_KEY_LENGTH, XWING_SECRET_KEY_LENGTH } from '../../src/constants'; describe('Test keystore create/open functions', async () => { const mockUserEmail = 'mock user email'; @@ -25,10 +25,10 @@ describe('Test keystore create/open functions', async () => { const result_rec = await openRecoveryKeystore(recoveryCodes, recoveryKeystore); expect(result_enc).toStrictEqual(result_rec); - expect(result_enc.privateKeys.eccPrivateKey).instanceOf(CryptoKey); - expect(result_enc.publicKeys.eccPublicKey).instanceOf(CryptoKey); - expect(result_enc.privateKeys.kyberPrivateKey.length).toBe(KYBER768_SECRET_KEY_LENGTH); - expect(result_enc.publicKeys.kyberPublicKey.length).toBe(KYBER768_PUBLIC_KEY_LENGTH); + expect(result_enc.publicKey).instanceOf(Uint8Array); + expect(result_enc.secretKey).instanceOf(Uint8Array); + expect(result_enc.publicKey.length).toBe(XWING_PUBLIC_KEY_LENGTH); + expect(result_enc.secretKey.length).toBe(XWING_SECRET_KEY_LENGTH); }); it('should throw an error if no base key for keystore opening', async () => { diff --git a/tests/utils/keyConverters.test.ts b/tests/utils/keyConverters.test.ts deleted file mode 100644 index 260fd4e..0000000 --- a/tests/utils/keyConverters.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { publicKeyToBase64, base64ToPublicKey } from '../../src/utils'; -import { PublicKeys } from '../../src/types'; -import { generateEccKeys } from '../../src/asymmetric-crypto'; -import { generateKyberKeys } from '../../src/post-quantum-crypto'; - -describe('key converters', () => { - it('public and private key converter to base64 and back works', async () => { - const eccKeyPair = await generateEccKeys(); - const kyberKeyPair = await generateKyberKeys(); - - const key: PublicKeys = { - eccPublicKey: eccKeyPair.publicKey, - kyberPublicKey: kyberKeyPair.publicKey, - }; - const base64 = await publicKeyToBase64(key); - const result = await base64ToPublicKey(base64); - expect(result).toEqual(key); - }); - - it('throws error if key converter to base64 fails', async () => { - const eccKeyPair = await generateEccKeys(); - const kyberKeyPair = await generateKyberKeys(); - - const bad_key: PublicKeys = { - eccPublicKey: eccKeyPair.privateKey, - kyberPublicKey: kyberKeyPair.publicKey, - }; - await expect(publicKeyToBase64(bad_key)).rejects.toThrowError( - /Failed to convert key of the type PublicKeys to PublicKeysBase64/, - ); - }); -});