diff --git a/src/misc.ts b/src/misc.ts index b9e41d2..5992c40 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -11,13 +11,31 @@ export enum Usage { 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)) + const pubkey_str = a2b64(new Uint8Array(pubkey_buff)) + + const usage = (pubkey.usages.includes('verify') ? Usage.sign : Usage.ecdh).toString() + + return `${usage}${pubkey_str}` } -export async function pubkey_fromString(pubkey_str: string, usage: Usage): Promise { +export async function pubkey_fromString(pubkey_str: string): Promise { log.trace('pubkey_fromString') - const pubkey = b642a(pubkey_str) + let usage: Usage; + const c = pubkey_str.at(0) + if (c === undefined) { + log.warn('Empty string ?') + return null + } else if (c === Usage.sign.toString()) usage = Usage.sign + else if (c === Usage.ecdh.toString()) usage = Usage.ecdh + else { + log.warn('Unknown usage encoded') + log.debug('Usage :', c) + return null + } + + const pubkey = b642a(pubkey_str.slice(1)) if (pubkey === null) return null try { @@ -37,15 +55,32 @@ export async function pubkey_fromString(pubkey_str: string, usage: Usage): Promi export async function pubkey_toBytes(pubkey: CryptoKey): Promise { log.trace('pubkey_toBytes') - return new Uint8Array(await crypto.subtle.exportKey('raw', pubkey)) + + const buf = new Uint8Array(await crypto.subtle.exportKey('raw', pubkey)) + const usage = pubkey.usages.includes('verify') ? Usage.sign : Usage.ecdh + + return new Uint8Array([usage, ...buf]) } -export async function pubkey_fromBytes(pubkey: Uint8Array, usage: Usage): Promise { +export async function pubkey_fromBytes(pubkey: Uint8Array): Promise { log.trace('pubkey_fromBytes') + let usage: Usage; + const o = pubkey.at(0) + if (o === undefined) { + log.warn('Empty array ?') + return null + } else if (o === Usage.sign) usage = Usage.sign + else if (o === Usage.ecdh) usage = Usage.ecdh + else { + log.warn('Unknown usage encoded') + log.debug('Usage :', o) + return null + } + try { return await crypto.subtle.importKey( 'raw', - pubkey, + pubkey.slice(1), usage === Usage.ecdh ? ECDH_PARAMETERS() : SIGNATURE_KEY(), true, usage === Usage.ecdh ? [] : ['verify'] diff --git a/src/private-box.ts b/src/private-box.ts index 03e0915..5bc8e31 100644 --- a/src/private-box.ts +++ b/src/private-box.ts @@ -75,7 +75,7 @@ export default class PrivateBox { log.warn('Data too short to contain pubkey') return null } - const pubkey = await pubkey_fromBytes(pubkey_buff, Usage.ecdh) + const pubkey = await pubkey_fromBytes(pubkey_buff) if (pubkey === null) return null const box = SecretBox.fromBytes(data.slice(1 + length)) @@ -88,6 +88,6 @@ export default class PrivateBox { return await misc.pubkey_toString(pubkey) } public static async pubkey_fromString(pubkey: string): Promise { - return await misc.pubkey_fromString(pubkey, misc.Usage.ecdh) + return await misc.pubkey_fromString(pubkey) } } diff --git a/src/private-wrap.ts b/src/private-wrap.ts index a665204..8f347cd 100644 --- a/src/private-wrap.ts +++ b/src/private-wrap.ts @@ -63,6 +63,6 @@ export default class PrivateWrap { return await misc.pubkey_toString(pubkey) } public static async pubkey_fromString(pubkey: string): Promise { - return await misc.pubkey_fromString(pubkey, misc.Usage.ecdh) + return await misc.pubkey_fromString(pubkey) } } diff --git a/src/signature.ts b/src/signature.ts index 73e6562..8be0d66 100644 --- a/src/signature.ts +++ b/src/signature.ts @@ -37,7 +37,7 @@ export async function pubkey_toString(pubkey: CryptoKey): Promise { return await misc.pubkey_toString(pubkey) } export async function pubkey_fromString(pubkey: string): Promise { - return await misc.pubkey_fromString(pubkey, misc.Usage.sign) + return await misc.pubkey_fromString(pubkey) } export function signature_toString(signature: Uint8Array): string { diff --git a/test/misc.test.ts b/test/misc.test.ts index d165d09..a8c6c45 100644 --- a/test/misc.test.ts +++ b/test/misc.test.ts @@ -1,13 +1,13 @@ import {expect, test} from 'bun:test' import {PrivateBox, PrivateWrap, SecretBox, signature} from '..' -import {pubkey_fromBytes, pubkey_fromString, pubkey_toBytes, pubkey_toString, Usage} from '../src/misc' +import {pubkey_fromBytes, pubkey_fromString, pubkey_toBytes, pubkey_toString} from '../src/misc' test('Private box', async () => { const message = crypto.getRandomValues(new Uint8Array(8)) const k = await PrivateBox.gen(false) const ser = await pubkey_toString(k.publicKey) - const de = await pubkey_fromString(ser, Usage.ecdh) + const de = await pubkey_fromString(ser) expect(de).not.toBeNull() const box = await PrivateBox.encrypt(message, de!) @@ -19,7 +19,7 @@ test('Private wrap', async () => { const k = await PrivateWrap.gen(false) const ser = await pubkey_toString(k.publicKey) - const de = await pubkey_fromString(ser, Usage.ecdh) + const de = await pubkey_fromString(ser) expect(de).not.toBeNull() const message = crypto.getRandomValues(new Uint8Array(8)) @@ -42,7 +42,7 @@ test('Signature', async () => { expect(signed).not.toBeNull() const ser = await pubkey_toString(k.publicKey) - const de = await pubkey_fromString(ser, Usage.sign) + const de = await pubkey_fromString(ser) expect(de).not.toBeNull() const verification = await signature.verify(message, de!, signed!) @@ -55,7 +55,7 @@ test('Byte serialization', async () => { expect(signed).not.toBeNull() const ser = await pubkey_toBytes(k.publicKey) - const de = await pubkey_fromBytes(ser, Usage.sign) + const de = await pubkey_fromBytes(ser) expect(de).not.toBeNull() const verification = await signature.verify(message, de!, signed!)