64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
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<CryptoKeyPair> {
|
|
log.trace("generate keypair")
|
|
return crypto.subtle.generateKey(
|
|
algorithm,
|
|
true,
|
|
["deriveKey"],
|
|
)
|
|
}
|
|
|
|
public static async encrypt(data: CryptoKey, pubkey: CryptoKey) : Promise<PrivateWrap> {
|
|
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<CryptoKey> {
|
|
log.trace("decrypt")
|
|
const kd = await ecdh(privkey, this.pubkey)
|
|
return this.box.decrypt(kd)
|
|
}
|
|
|
|
public async toString(): Promise<string> {
|
|
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<PrivateWrap> {
|
|
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)
|
|
}
|
|
}
|