import logger from 'log' import SecretBox from './secret-box' import {DHusage, ecdh} from './kdf' import {pubkey_fromString, pubkey_toString, Usage} from './misc' import * as consts from './const' const log = logger('crypto:private-box') export default class PrivateBox { private constructor( private readonly pubkey: CryptoKey, private readonly box: SecretBox ) {} public static gen(extractable: boolean = true): Promise { log.trace('generate keypair') log.trace('Extractable :', extractable) try { return crypto.subtle.generateKey(consts.ECDH, extractable, ['deriveKey']) as Promise } catch (e) { log.warn('Failed to generate a key') log.debug('Error :', e) throw e } } public static async encrypt(data: Uint8Array, pubkey: CryptoKey): Promise { log.trace('encrypt') const tmp_pair = await PrivateBox.gen(false) const key = await ecdh(tmp_pair.privateKey, pubkey, DHusage.box) const box = await SecretBox.encrypt(data, key) return new this(tmp_pair.publicKey, box) } public async decrypt(privkey: CryptoKey): Promise { log.trace('decrypt') const key = await ecdh(privkey, this.pubkey, DHusage.box) return this.box.decrypt(key) } public async toString(): Promise { log.trace('toString') const pubkey = await 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 pubkey_fromString(parts[0], Usage.ecdh) if (pubkey === null) return null const box = SecretBox.fromString(parts.slice(1).join('.')) if (box === null) return null return new PrivateBox(pubkey, box) } }