import { AsymmetricDataEncryptor, EncryptedData } from "./asymmetric-data-encryptor"; import { JSONValue } from "encoding/json/types"; import { HalfCryptoKeyPair } from "encryption/types"; import { KeyEncoder } from "encoding/key"; import { DecryptionError } from "error"; export interface ApplicationDataEncryptorI { encrypt(jsonableInput: JSONValue): Promise; decrypt( encryptedObj: EncryptedData, encryptedKeyOverride?: string ): Promise; update( newData: JSONValue, existingEncryptedObject: EncryptedData, encryptedKeyOverride?: string ): Promise; share( encryptedObj: EncryptedData, publicKeyObj: JsonWebKey, sharedDataKey: string ): Promise; exportPublicKey(): Promise; encryptPrivateKey( publicKeyObjToShareWith: JsonWebKey ): Promise; } export function ApplicationDataEncryptor( encryptionKeyPair: CryptoKeyPair | HalfCryptoKeyPair ): ApplicationDataEncryptorI { const dataEncryptor = AsymmetricDataEncryptor(encryptionKeyPair); return { encrypt: dataEncryptor.encrypt, decrypt: dataEncryptor.decrypt, update: dataEncryptor.update, share: dataEncryptor.share, exportPublicKey: dataEncryptor.exportPublicKey, encryptPrivateKey: dataEncryptor.encryptPrivateKey }; } ApplicationDataEncryptor.getDefaultAlgorithm = AsymmetricDataEncryptor.getDefaultAlgorithm; ApplicationDataEncryptor.generateKeyPair = AsymmetricDataEncryptor.generateKeyPair; ApplicationDataEncryptor.create = async function(): Promise< ApplicationDataEncryptorI > { const keyPair = await ApplicationDataEncryptor.generateKeyPair(); return ApplicationDataEncryptor(keyPair); }; ApplicationDataEncryptor.decodePublicKey = AsymmetricDataEncryptor.decodePublicKey; ApplicationDataEncryptor.loadForEncryption = async function( publicKeyObj: JsonWebKey ): Promise { const publicKey = await ApplicationDataEncryptor.decodePublicKey( publicKeyObj ); return ApplicationDataEncryptor({ publicKey }); }; ApplicationDataEncryptor.loadForDecryption = async function( publicKeyObj: JsonWebKey, usersPrivateKey: CryptoKey, encryptedPrivateKey: EncryptedData ): Promise { const publicKey = await ApplicationDataEncryptor.decodePublicKey( publicKeyObj ); const privateKeyEncryptor = AsymmetricDataEncryptor({ privateKey: usersPrivateKey }); let decryptedPrivateKeyData; try { decryptedPrivateKeyData = await privateKeyEncryptor.decrypt( encryptedPrivateKey ); } catch (error) { throw new DecryptionError( "The WAEPriK (Wrapped Application Encryption Private Key) for this application cannot be decrypted by this user.", "It probably belongs to another user." ); } // We encoded it manually in the process of encryption, so we'll also decode it manually here const privateKey = await KeyEncoder().decode( decryptedPrivateKeyData as JsonWebKey, ApplicationDataEncryptor.getDefaultAlgorithm(), ["unwrapKey"], // We want to be able to share this key with others, so it needs to be // extractable true ); return ApplicationDataEncryptor({ publicKey, privateKey }); };