import { DataEncryptor } from "encryption/data/data-encryptor"; import { AESKeyEncryptorI, EncryptedKey } from "encryption/low-level/symmetric/aes/key"; import { DecryptionError } from "error"; import { KeyEncoder } from "encoding/key"; // We'll use PKCS8 for private keys as they are much shorter // than JWK keys, and won't be human readable anyway (as they'll // be encrypted) const privateKeyExportFormat = "pkcs8"; export interface EncryptedKeyPair { public_key: JsonWebKey; private_key: EncryptedKey; } export interface ExportedKeyPair { public_key: JsonWebKey; private_key: JsonWebKey; } const keyTypes = { encryption: { algorithm: DataEncryptor.getDefaultAsymmetricEncryptionAlgorithm(), usages: { publicKey: ["wrapKey"] as KeyUsage[], privateKey: ["unwrapKey"] as KeyUsage[] } }, signing: { algorithm: DataEncryptor.getDefaultSigningAlgorithm(), usages: { publicKey: ["verify"] as KeyUsage[], privateKey: ["sign"] as KeyUsage[] } } }; export async function encryptKeyPair( privateKeyEncryptor: AESKeyEncryptorI, asymmetricKeyPair: CryptoKeyPair ): Promise { const { publicKey, privateKey } = asymmetricKeyPair; return { // eslint-disable-next-line @typescript-eslint/camelcase public_key: await KeyEncoder().encode(publicKey), // eslint-disable-next-line @typescript-eslint/camelcase private_key: await privateKeyEncryptor.encryptKey( privateKey, privateKeyExportFormat ) }; } export async function exportKeyPair( asymmetricKeyPair: CryptoKeyPair ): Promise { const { publicKey, privateKey } = asymmetricKeyPair; return { // eslint-disable-next-line @typescript-eslint/camelcase public_key: await KeyEncoder().encode(publicKey), // eslint-disable-next-line @typescript-eslint/camelcase private_key: await KeyEncoder().encode(privateKey) }; } export async function decryptKeyPair( privateKeyEncryptor: AESKeyEncryptorI, keyPairObject: EncryptedKeyPair, type: "encryption" | "signing", extractable: boolean ): Promise { const { public_key: encodedPublic, private_key: encryptedPrivate } = keyPairObject; const { algorithm, usages } = keyTypes[type]; const publicKey = await KeyEncoder().decode( encodedPublic, algorithm, usages.publicKey, extractable ); let privateKey; try { privateKey = await privateKeyEncryptor.decryptKey( encryptedPrivate, algorithm, extractable, privateKeyExportFormat, usages.privateKey ); } catch (error) { throw new DecryptionError( "Failed to decrypt WUEPriK (Wrapped User Encryption Private Key) with the supplied password.", "The password is probably incorrect." ); } return { publicKey, privateKey }; } export async function importKeyPair( exportedKeyPair: ExportedKeyPair, type: "encryption" | "signing", extractable: boolean ): Promise { const { public_key: encodedPublic, private_key: encodedPrivate } = exportedKeyPair; const { algorithm, usages } = keyTypes[type]; return { publicKey: await KeyEncoder().decode( encodedPublic, algorithm, usages.publicKey, extractable ), privateKey: await KeyEncoder().decode( encodedPrivate, algorithm, usages.privateKey, extractable ) }; }