diff --git a/index.ts b/index.ts index 2225b2d..0fbc1ab 100644 --- a/index.ts +++ b/index.ts @@ -1,9 +1,13 @@ -import {ecdh, hkdf, pbkdf, Usage} from "./src/kdf" +import SecretBox from './src/secret-box' +import SecretWrap from './src/secret-wrap' +import PrivateBox from './src/private-box' +import PrivateWrap from './src/private-wrap' +import PwdBox from './src/pwd-box' +import PwdWrap from './src/pwd-wrap' -export const kdf = {ecdh, hkdf, pbkdf, Usage} -export * as signature from "./src/signature" -export * as JWT from "./src/jwt" -export {SecretBox} from './src/secret-box' -export {PrivateWrap} from './src/private-wrap' -export {SecretWrap} from './src/secret-wrap' -export {PwdWrap} from './src/pwd-wrap' +export * as kdf from './src/kdf' +export * as misc from './src/misc' +export * as signature from './src/signature' +export * as JWT from './src/jwt' + +export {SecretBox,SecretWrap,PrivateBox,PrivateWrap,PwdBox,PwdWrap} diff --git a/src/const.ts b/src/const.ts new file mode 100644 index 0000000..709b4a3 --- /dev/null +++ b/src/const.ts @@ -0,0 +1,4 @@ +export const ECDH = {name: 'ECDH', namedCurve: 'P-521'} +export const SIGNATURE_KEY = {name: 'ECDSA', namedCurve: 'P-521'} +export const SIGNATURE_ALGO = {name: 'ECDSA', hash: 'SHA-512'} +export const ENCRYPTION = 'AES-GCM' diff --git a/src/kdf.ts b/src/kdf.ts index 8d1358f..2635d41 100644 --- a/src/kdf.ts +++ b/src/kdf.ts @@ -1,47 +1,72 @@ import logger from 'log' +import * as consts from './const' const log = logger('crypto:kdf') export enum Usage { - sign, + box, + wrap + // sign +} +export enum DHusage { + box, wrap } -export async function hkdf(key: Uint8Array, usage: Usage): Promise { + +export async function hkdf(key: Uint8Array, usage: Usage): Promise { log.trace('HKDF') - log.trace(`usage : ${usage === Usage.sign ? 'sign' : 'wrap'}`) + log.trace(`usage : ${usage}`) const material = await crypto.subtle.importKey('raw', key, 'HKDF', false, ['deriveKey', 'deriveBits']) - if (usage === Usage.wrap) { - return crypto.subtle.deriveKey( + let algo + let usages: KeyUsage[] + let info_txt: string + switch (usage) { + /*case Usage.sign: { + algo = 'Ed215519' + usages = ['sign', 'verify'] + info_txt = 'sign' + } break;*/ + case Usage.box: { - name: 'HKDF', - hash: 'SHA-512', - salt: new Uint8Array(32), - info: new TextEncoder().encode('wrap') - }, - material, - {name: 'AES-GCM', length: 256}, - false, - ['wrapKey', 'unwrapKey'] - ) - } else if (usage === Usage.sign) { - const buffer = await crypto.subtle.deriveBits( + algo = { + name: consts.ENCRYPTION, + length: 256 + } + usages = ['encrypt', 'decrypt'] + info_txt = 'box' + } + break + case Usage.wrap: { - name: 'HKDF', - hash: 'SHA-512', - salt: new Uint8Array(32), - info: new TextEncoder().encode('sign') - }, - material, - 512 - ) - return new Uint8Array(buffer) - } else { - log.warn(`Called HKDF with unknown enum value : ${usage}`) - throw "I don't even know what to say." + algo = { + name: consts.ENCRYPTION, + length: 256 + } + usages = ['wrapKey', 'unwrapKey'] + info_txt = 'wrap' + } + break + default: { + log.warn(`Unknown usage '${usage}'`) + throw 'Unknown usage for HDKF' + } } -} + const info = new TextEncoder().encode(info_txt) + return crypto.subtle.deriveKey( + { + name: 'HKDF', + hash: 'SHA-512', + salt: new Uint8Array(32), + info + }, + material, + algo, + false, + usages + ) +} export async function pbkdf(salt: Uint8Array, password: string): Promise { log.trace('PBKDF') const material = await crypto.subtle.importKey('raw', new TextEncoder().encode(password), 'PBKDF2', false, [ @@ -61,20 +86,20 @@ export async function pbkdf(salt: Uint8Array, password: string): Promise { - log.trace('ECDH') +export function ecdh(privkey: CryptoKey, pubkey: CryptoKey, usage: DHusage): Promise { + log.trace("ecdh") + const outputUsage: KeyUsage[] = usage === DHusage.box ? ['encrypt', 'decrypt'] : ['wrapKey', 'unwrapKey'] return crypto.subtle.deriveKey( { - name: 'ECDH', + name: consts.ECDH.name, public: pubkey }, privkey, { - name: 'AES-GCM', + name: consts.ENCRYPTION, length: 256 }, false, - ['wrapKey', 'unwrapKey'] + outputUsage ) } diff --git a/src/misc.ts b/src/misc.ts new file mode 100644 index 0000000..b7bc134 --- /dev/null +++ b/src/misc.ts @@ -0,0 +1,36 @@ +import logger from 'log' +import {a2b64, b642a} from 'misc' +import * as consts from './const' + +const log = logger('misc') + +export enum Usage { + sign, + ecdh, +} + +export async function pubkey_toString(pubkey: CryptoKey): Promise { + log.trace('pubkey_toString') + const pubkey_buff = await crypto.subtle.exportKey('spki', pubkey) + return a2b64(new Uint8Array(pubkey_buff)) +} +export async function pubkey_fromString(pubkey_str: string, usage: Usage): Promise { + log.trace('pubkey_fromString') + + const pubkey = b642a(pubkey_str) + if (pubkey === null) return null + + try { + return await crypto.subtle.importKey( + 'spki', + pubkey, + usage === Usage.ecdh ? consts.ECDH : consts.SIGNATURE_KEY, + true, + usage === Usage.ecdh ? [] : ['verify'] + ) + } catch (e) { + log.warn("Failed to import public key") + log.debug("Error :", e) + return null + } +} diff --git a/src/private-box.ts b/src/private-box.ts new file mode 100644 index 0000000..0aaf79b --- /dev/null +++ b/src/private-box.ts @@ -0,0 +1,59 @@ +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) + } +} diff --git a/src/private-wrap.ts b/src/private-wrap.ts index 95576c3..008cc87 100644 --- a/src/private-wrap.ts +++ b/src/private-wrap.ts @@ -1,68 +1,52 @@ -import {a2b64, b642a} from 'misc' import logger from 'log' - -import {SecretWrap} from './secret-wrap' -import {ecdh} from './kdf' +import {DHusage, ecdh} from './kdf' +import SecretWrap from './secret-wrap' +import {pubkey_fromString, pubkey_toString, Usage} from './misc' +import * as consts from './const' const log = logger('crypto:private-wrap') -const algorithm = { - name: 'ECDH', - namedCurve: 'P-521' -} +export default class PrivateWrap { + private constructor( + private readonly box: SecretWrap, + private readonly pubkey: CryptoKey + ) {} -export class PrivateWrap { - private constructor(private readonly box: SecretWrap, private readonly pubkey: CryptoKey) {} - - public static gen_keypair(extractable: boolean = true): Promise { + public static gen(extractable: boolean = true): Promise { log.trace('generate keypair') - return crypto.subtle.generateKey(algorithm, extractable, ['deriveKey']) + return crypto.subtle.generateKey(consts.ECDH, extractable, ['deriveKey']) as Promise } 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 tmp_keypair = await PrivateWrap.gen() + const kd = await ecdh(tmp_keypair.privateKey, pubkey, DHusage.wrap) const box = await SecretWrap.encrypt(data, kd) - return new this(box, k.publicKey) + return new this(box, tmp_keypair.publicKey) } - public async decrypt(privkey: CryptoKey): Promise { + public async decrypt(privkey: CryptoKey): Promise { log.trace('decrypt') - const kd = await ecdh(privkey, this.pubkey) + const kd = await ecdh(privkey, this.pubkey, DHusage.wrap) return this.box.decrypt(kd) } public async toString(): Promise { log.trace('toString') - const pubkey = await PrivateWrap.publicKey_toString(this.pubkey) + 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('.', 2) - if (parts.length !== 2) return null + const parts = data.split('.') + if (parts.length < 2) return null - const pubkey = await this.publicKey_fromString(parts[0]) + const pubkey = await pubkey_fromString(parts[0], Usage.ecdh) if (pubkey === null) return null - const box = SecretWrap.fromString(parts[1]) + const box = SecretWrap.fromString(parts.slice(1).join(".")) if (box === null) return null return new PrivateWrap(box, pubkey) } - - public static async publicKey_toString(publicKey: CryptoKey): Promise { - const pubkey_spki = await crypto.subtle.exportKey('spki', publicKey) - return a2b64(new Uint8Array(pubkey_spki)) - } - public static async publicKey_fromString(data: string): Promise { - const pubkey_str = b642a(data) - if (pubkey_str.is_err()) return null - try { - return crypto.subtle.importKey('spki', pubkey_str.unwrap(), algorithm, true, []) - } catch(e) { - return null - } - } } diff --git a/src/pwd-box.ts b/src/pwd-box.ts new file mode 100644 index 0000000..b760052 --- /dev/null +++ b/src/pwd-box.ts @@ -0,0 +1,51 @@ +import logger from 'log' +import {hkdf, pbkdf, Usage} from './kdf' +import SecretBox from './secret-box' +import {a2b64, b642a} from 'misc' + +const log = logger('crypto:pwd-box') + +export default class PwdBox { + private constructor( + private readonly box: SecretBox, + private readonly salt: Uint8Array + ) {} + + private static async derive(pwd: string, salt: Uint8Array): Promise { + const k = await pbkdf(salt, pwd) + return (await hkdf(k, Usage.box)) as CryptoKey + } + + public static async encrypt(data: Uint8Array, pwd: string): Promise { + log.trace('encrypt') + const salt = crypto.getRandomValues(new Uint8Array(16)) + const k = await PwdBox.derive(pwd, salt) + const box = await SecretBox.encrypt(data, k) + return new PwdBox(box, salt) + } + public async decrypt(pwd: string): Promise { + log.trace('decrypt') + const k = await PwdBox.derive(pwd, this.salt) + return this.box.decrypt(k) + } + + public toString(): string { + log.trace('toString') + const salt = a2b64(this.salt) + const box = this.box.toString() + return `${salt}.${box}` + } + public static fromString(data: string): PwdBox | null { + log.trace('fromString') + + const parts = data.split('.') + if (parts.length < 2) return null + + const salt = b642a(parts[0]) + if (salt === null) return null + const box = SecretBox.fromString(parts.slice(1).join(".")) + if (box === null) return null + + return new PwdBox(box, salt) + } +} diff --git a/src/pwd-wrap.ts b/src/pwd-wrap.ts index abd4c79..99bdc0d 100644 --- a/src/pwd-wrap.ts +++ b/src/pwd-wrap.ts @@ -1,49 +1,52 @@ import {hkdf, pbkdf, Usage} from './kdf' -import {SecretWrap} from './secret-wrap' +import SecretWrap from './secret-wrap' import logger from 'log' -import {a2b64, b642a} from "misc"; +import {a2b64, b642a} from 'misc' const log = logger('crypto:pwd-wrap') -export class PwdWrap { - private constructor(private readonly box: SecretWrap, private readonly salt: Uint8Array) {} +export default class PwdWrap { + private constructor( + private readonly box: SecretWrap, + private readonly salt: Uint8Array + ) {} - private static async derive(pwd: string, salt: Uint8Array) : Promise { - const k = await pbkdf(salt, pwd) - return await hkdf(k, Usage.wrap) as CryptoKey - } + private static async derive(pwd: string, salt: Uint8Array): Promise { + const k = await pbkdf(salt, pwd) + return (await hkdf(k, Usage.wrap)) as CryptoKey + } - public static async encrypt(data: CryptoKey, pwd: string, salt?: Uint8Array) : Promise { - log.trace('encrypt') - salt = salt ?? crypto.getRandomValues(new Uint8Array(16)) - const k = await PwdWrap.derive(pwd, salt) - const box = await SecretWrap.encrypt(data, k) - return new PwdWrap(box, salt) - } - public async decrypt(pwd: string) : Promise { - log.trace('decrypt') - const k = await PwdWrap.derive(pwd, this.salt) - return this.box.decrypt(k) - } + public static async encrypt(data: CryptoKey, pwd: string, salt?: Uint8Array): Promise { + log.trace('encrypt') + salt = salt ?? crypto.getRandomValues(new Uint8Array(16)) + const k = await PwdWrap.derive(pwd, salt) + const box = await SecretWrap.encrypt(data, k) + return new PwdWrap(box, salt) + } + public async decrypt(pwd: string): Promise { + log.trace('decrypt') + const k = await PwdWrap.derive(pwd, this.salt) + return this.box.decrypt(k) + } - public toString(): String { - log.trace('toString') - const salt = a2b64(this.salt) - const box = this.box.toString() - return `${salt}.${box}` - } + public toString(): string { + log.trace('toString') + const salt = a2b64(this.salt) + const box = this.box.toString() + return `${salt}.${box}` + } - public fromString(data: string): PwdWrap | null { - log.trace('fromString') + public static fromString(data: string): PwdWrap | null { + log.trace('fromString') - const parts = data.split('.', 2) - if (parts.length !== 2) return null + const parts = data.split('.') + if (parts.length < 2) return null - const salt = b642a(parts[0]) - if (salt.is_err()) return null - const box = SecretWrap.fromString(parts[1]) - if (box === null) return null + const salt = b642a(parts[0]) + if (salt === null) return null + const box = SecretWrap.fromString(parts.slice(1).join(".")) + if (box === null) return null - return new PwdWrap(box, salt.unwrap()) - } + return new PwdWrap(box, salt) + } } diff --git a/src/secret-box.ts b/src/secret-box.ts index 36900e7..8d897dd 100644 --- a/src/secret-box.ts +++ b/src/secret-box.ts @@ -1,16 +1,20 @@ import logger from 'log' import {a2b64, b642a} from 'misc' +import * as consts from './const' const log = logger('crypto:secret-box') -export class SecretBox { - private constructor(private readonly iv: Uint8Array, private readonly cipher: Uint8Array) {} +export default class SecretBox { + private constructor( + private readonly iv: Uint8Array, + private readonly cipher: Uint8Array + ) {} - public static gen_key(extractable: boolean = true): Promise { + public static gen(extractable: boolean = true): Promise { log.trace('generate key') return crypto.subtle.generateKey( { - name: 'AES-GCM', + name: consts.ENCRYPTION, length: 256 }, extractable, @@ -23,7 +27,7 @@ export class SecretBox { const iv = crypto.getRandomValues(new Uint8Array(11)) const cipher = await crypto.subtle.encrypt( { - name: 'AES-GCM', + name: consts.ENCRYPTION, iv }, key, @@ -31,30 +35,47 @@ export class SecretBox { ) return new SecretBox(iv, new Uint8Array(cipher)) } - public async decrypt(key: CryptoKey): Promise { + public async decrypt(key: CryptoKey): Promise { log.trace('decrypt') - const buffer = await crypto.subtle.decrypt( - { - name: 'AES-GCM', - iv: this.iv - }, - key, - this.cipher - ) - return new Uint8Array(buffer) + try { + const buffer = await crypto.subtle.decrypt( + { + name: consts.ENCRYPTION, + iv: this.iv + }, + key, + this.cipher + ) + return new Uint8Array(buffer) + } catch(e) { + log.warn("Failed to decrypt") + log.debug("Error :", e) + return null + } } public toString(): string { log.trace('toString') + const iv = a2b64(this.iv) - const cipher = a2b64(this.iv) + const cipher = a2b64(this.cipher) + return `${iv}.${cipher}` } - public static fromString(data: string): SecretBox { + public static fromString(data: string): SecretBox | null { log.trace('fromString') - const parts = data.split('.', 2) - const iv = b642a(parts[0]).expect('Failed decode IV') - const cipher = b642a(parts[1]).expect('Failed to decode cipher') + + const parts = data.split('.') + if (parts.length < 2) { + log.warn("Invalid parts count") + return null + } + + const iv = b642a(parts[0]) + if (iv === null) return null + const cipher = b642a(parts[1]) + if (cipher === null) return null + return new SecretBox(iv, cipher) } } diff --git a/src/secret-wrap.ts b/src/secret-wrap.ts index 38e530b..aab567b 100644 --- a/src/secret-wrap.ts +++ b/src/secret-wrap.ts @@ -1,9 +1,10 @@ import logger from 'log' import {a2b64, b642a} from 'misc' +import * as consts from './const' const log = logger('crypto:secret-wrap') -export class SecretWrap { +export default class SecretWrap { constructor( private readonly cipher: Uint8Array, private readonly algorithm: KeyAlgorithm, @@ -12,11 +13,11 @@ export class SecretWrap { private readonly iv: Uint8Array ) {} - public static gen_key(extractable: boolean = true): Promise { + public static gen(extractable: boolean = true): Promise { log.trace('generate key') return crypto.subtle.generateKey( { - name: 'AES-GCM', + name: consts.ENCRYPTION, length: 256 }, extractable, @@ -37,55 +38,51 @@ export class SecretWrap { public static async encrypt(data: CryptoKey, key: CryptoKey): Promise { log.trace('encrypt') - const format = this.format(data.type) + const format = SecretWrap.format(data.type) const iv = crypto.getRandomValues(new Uint8Array(12)) - const box = await crypto.subtle.wrapKey(format, data, key, { - name: 'AES-GCM', - iv - }) + const box = await crypto.subtle.wrapKey(format, data, key, {name: consts.ENCRYPTION, iv}) return new SecretWrap(new Uint8Array(box), data.algorithm, data.usages, format, iv) } - public async decrypt(key: CryptoKey): Promise { + public async decrypt(key: CryptoKey): Promise { log.trace('decrypt') - return crypto.subtle.unwrapKey( - this.type, - this.cipher, - key, - { - name: 'AES-GCM', - iv: this.iv - }, - this.algorithm, - true, - this.usages - ) + try { + return await crypto.subtle.unwrapKey(this.type, this.cipher, key, {name: consts.ENCRYPTION, iv: this.iv}, this.algorithm, true, this.usages) + } catch(e) { + log.warn("Failed to unwrap") + log.debug("Error :", e) + return null + } } public toString(): string { log.trace('toString') + const iv = a2b64(this.iv) return JSON.stringify({ cipher: a2b64(this.cipher), - iv: a2b64(this.iv), algorithm: this.algorithm, usages: this.usages, - type: this.type + type: this.type, + iv, }) } public static fromString(data: string): SecretWrap | null { log.trace('fromString') - const obj = this.parseJSON(data) + const obj = SecretWrap.parseJSON(data) if (obj === null) return null const cipher = b642a(obj.cipher) - if (cipher.is_err()) return null - const iv = b642a(obj.iv) - if (iv.is_err()) return null + if (cipher === null) return null - return new SecretWrap(cipher.unwrap(), obj.algorithm, obj.usages, obj.type, iv.unwrap()) + const iv = b642a(obj.iv) + if (iv === null) return null + + return new SecretWrap(cipher, obj.algorithm, obj.usages, obj.type, iv) } - private static parseJSON(data: string): {cipher: string, iv: string, algorithm: KeyAlgorithm, usages: KeyUsage[], type: 'raw' | 'pkcs8'} | null { + private static parseJSON( + data: string + ): {cipher: string; iv: string; algorithm: KeyAlgorithm; usages: KeyUsage[]; type: 'raw' | 'pkcs8'} | null { log.trace('parseJSON') try { // TODO : Check the fields diff --git a/src/signature.derive.ts b/src/signature.derive.ts deleted file mode 100644 index eba76a5..0000000 --- a/src/signature.derive.ts +++ /dev/null @@ -1,80 +0,0 @@ -import {p521} from '@noble/curves/p521' -import {hexToNumber, bytesToHex, hexToBytes, numberToHexUnpadded} from '@noble/curves/abstract/utils' -import {sha512} from '@noble/hashes/sha512' -import {hkdf} from '@noble/hashes/hkdf' -import * as mod from '@noble/curves/abstract/modular' -import type {ProjPointType} from '@noble/curves/abstract/weierstrass' - -/** Derive a keypair from random data with sufficient entropy - * @param source entropy source, 64 bytes - * @returns [PrivKey, PubKey] - */ -export async function derive_keypair(source: Uint8Array): Promise<[CryptoKey, CryptoKey]> { - const derived = hkdf(sha512, source, undefined, 'sign', 512) - const validPrivateKey = mod.mapHashToField(derived, p521.CURVE.n) // Dodge modulus bias :) (kinda) - const d = a2bg(validPrivateKey) - const point = get_pubkey(d) - - const pubkey = await crypto_pubkey(point) - const privkey = await crypto_privkey(d, point) - - return [privkey, pubkey] -} -function get_pubkey(d: bigint): ProjPointType { - return p521.ProjectivePoint.BASE.multiply(d) -} -function crypto_privkey(d: bigint, point: ProjPointType): Promise { - const jwk = { - crv: 'P-521', - d: bg2b64url(d), - ext: false, - key_ops: ['sign'], - kty: 'EC', - x: bg2b64url(point.x), - y: bg2b64url(point.y) - } - return crypto.subtle.importKey( - 'jwk', - jwk, - { - name: 'ECDSA', - namedCurve: 'P-521' - }, - false, - ['sign'] - ) -} -function crypto_pubkey(point: ProjPointType): Promise { - const jwk = { - crv: 'P-521', - ext: true, - key_ops: ['verify'], - kty: 'EC', - x: bg2b64url(point.x), - y: bg2b64url(point.y) - } - return crypto.subtle.importKey( - 'jwk', - jwk, - { - name: 'ECDSA', - namedCurve: 'P-521' - }, - true, - ['verify'] - ) -} -function bg2b64url(n: bigint): string { - return encode(btoa(String.fromCharCode(...hexToBytes(numberToHexUnpadded(n))))) -} -function encode(input: string): string { - // Replace non-url compatible chars with base64 standard chars - input = input.replace(/\+/g, '-').replace(/\//g, '_') - - const last = input.lastIndexOf('=') - if (last > 0) return input.substring(0, last) - return input -} -function a2bg(data: Uint8Array): bigint { - return hexToNumber(bytesToHex(data)) -} diff --git a/src/signature.ts b/src/signature.ts index 4325384..6e3f154 100644 --- a/src/signature.ts +++ b/src/signature.ts @@ -1,38 +1,16 @@ import logger from 'log' const log = logger('crypto:signature') +import * as consts from './const' -export async function gen_keypair(extractable: boolean = true): Promise { - return crypto.subtle.generateKey( - { - name: 'ECDSA', - namedCurve: 'P-521' - }, - extractable, - ['sign', 'verify'] - ) +export async function gen(extractable: boolean = true): Promise { + return crypto.subtle.generateKey(consts.SIGNATURE_KEY, extractable, ['sign', 'verify']) } -export {derive_keypair} from './signature.derive' export async function sign(message: Uint8Array, privkey: CryptoKey): Promise { log.trace('sign') - const buffer = await crypto.subtle.sign( - { - name: 'ECDSA', - hash: 'SHA-512' - }, - privkey, - message - ) + const buffer = await crypto.subtle.sign(consts.SIGNATURE_ALGO, privkey, message) return new Uint8Array(buffer) } export async function verify(message: Uint8Array, pubkey: CryptoKey, signature: Uint8Array): Promise { log.trace('verify') - return crypto.subtle.verify( - { - name: 'ECDSA', - hash: 'SHA-512' - }, - pubkey, - signature, - message - ) + return crypto.subtle.verify(consts.SIGNATURE_ALGO, pubkey, signature, message) }