import logger from 'log' import {DHusage, ecdh} from './kdf' import SecretWrap from './secret-wrap' import * as misc from './misc' import * as consts from './const' const log = logger('crypto:private-wrap') export default class PrivateWrap { private constructor( private readonly box: SecretWrap, private readonly pubkey: CryptoKey ) {} public static async gen(extractable: boolean = true): Promise { log.trace('generate keypair') return await crypto.subtle.generateKey(consts.ECDH, extractable, ['deriveKey']) as CryptoKeyPair } public static async wrap(data: CryptoKey, pubkey: CryptoKey): Promise { log.trace('wrap') const tmp_keypair = await PrivateWrap.gen() const kd = await ecdh(tmp_keypair.privateKey, pubkey, DHusage.wrap) const box = await SecretWrap.wrap(data, kd) return new this(box, tmp_keypair.publicKey) } public async unwrap(privkey: CryptoKey): Promise { log.trace('unwrap') const kd = await ecdh(privkey, this.pubkey, DHusage.wrap) return await this.box.unwrap(kd) } public async toString(): Promise { log.trace('toString') const pubkey = await PrivateWrap.pubkey_toString(this.pubkey) const box = this.box.toString() return `${pubkey}.${box}` } public static async fromString(data: string): Promise { log.trace('fromString') const parts = data.split('.') if (parts.length < 2) return null const pubkey = await PrivateWrap.pubkey_fromString(parts[0]) if (pubkey === null) return null const box = SecretWrap.fromString(parts.slice(1).join('.')) if (box === null) return null return new PrivateWrap(box, pubkey) } public static async pubkey_toString(pubkey: CryptoKey): Promise { return await misc.pubkey_toString(pubkey) } public static async pubkey_fromString(pubkey: string): Promise { return await misc.pubkey_fromString(pubkey, misc.Usage.ecdh) } }