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) } }