From 8cb424db6768a7b272d39ab9f50f8be97f22a929 Mon Sep 17 00:00:00 2001 From: Pascal Perrenoud Date: Thu, 6 Jun 2024 01:50:01 +0200 Subject: [PATCH] Implement private-wrap --- src/private-wrap.ts | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/private-wrap.ts diff --git a/src/private-wrap.ts b/src/private-wrap.ts new file mode 100644 index 0000000..5352079 --- /dev/null +++ b/src/private-wrap.ts @@ -0,0 +1,63 @@ +import {a2b64, b642a} from 'misc' +import logger from 'log' + +import {SecretWrap} from './secret-wrap' +import {ecdh} from './kdf' + +const log = logger('crypto:private-wrap') + +const algorithm = { + name: "ECDH", + namedCurve: "P-521", +} + +export class PrivateWrap { + private constructor( + private readonly box: SecretWrap, + private readonly pubkey: CryptoKey, + ) {} + + public static gen_keypair() : Promise { + log.trace("generate keypair") + return crypto.subtle.generateKey( + algorithm, + true, + ["deriveKey"], + ) + } + + public static async encrypt(data: CryptoKey, pubkey: CryptoKey) : Promise { + log.trace("encrypt") + const k = await this.gen_keypair() + const kd = await ecdh(k.privateKey, pubkey) + const box = await SecretWrap.encrypt(data, kd) + return new this(box, k.publicKey) + } + public async decrypt(privkey: CryptoKey) : Promise { + log.trace("decrypt") + const kd = await ecdh(privkey, this.pubkey) + return this.box.decrypt(kd) + } + + public async toString(): Promise { + log.trace("toString") + const pubkey_spki = await crypto.subtle.exportKey("spki", this.pubkey) + const pubkey = a2b64(new Uint8Array(pubkey_spki)) + const box = this.box.toString() + return `${pubkey}.${box}` + } + public static async fromString(data: string): Promise { + log.trace("fromString") + const parts = data.split(".", 2) + const pubkey_str = b642a(parts[0]).expect("Failed to decode pubkey") + const pubkey = await crypto.subtle.importKey( + "spki", + pubkey_str, + algorithm, + true, + [], + ) + const box = SecretWrap.fromString(parts[1]) + return new PrivateWrap(box, pubkey) + } +}