From b92407b156ca9f704b026078b7c0ececc1c88221 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Wed, 16 Aug 2023 09:53:37 -0700 Subject: [PATCH] nip44 updates (#278) Co-authored-by: Jonathan Staab --- nip44.test.ts | 10 ++++++---- nip44.ts | 39 ++++++++++++++------------------------- 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/nip44.test.ts b/nip44.test.ts index 1dfe4b8..1bf348b 100644 --- a/nip44.test.ts +++ b/nip44.test.ts @@ -1,6 +1,7 @@ import crypto from 'node:crypto' +import {hexToBytes} from '@noble/hashes/utils' -import {encrypt, decrypt} from './nip44.ts' +import {encrypt, decrypt, getSharedSecret} from './nip44.ts' import {getPublicKey, generatePrivateKey} from './keys.ts' // @ts-ignore @@ -12,8 +13,9 @@ test('encrypt and decrypt message', async () => { let sk2 = generatePrivateKey() let pk1 = getPublicKey(sk1) let pk2 = getPublicKey(sk2) + let sharedKey1 = getSharedSecret(sk1, pk2) + let sharedKey2 = getSharedSecret(sk2, pk1) - expect(await decrypt(sk2, pk1, await encrypt(sk1, pk2, 'hello'))).toEqual( - 'hello' - ) + expect(decrypt(hexToBytes(sk1), encrypt(hexToBytes(sk1), 'hello'))).toEqual('hello') + expect(decrypt(sharedKey2, encrypt(sharedKey1, 'hello'))).toEqual('hello') }) diff --git a/nip44.ts b/nip44.ts index 0e75164..4a12f94 100644 --- a/nip44.ts +++ b/nip44.ts @@ -6,51 +6,40 @@ import {xchacha20} from '@noble/ciphers/chacha' import {utf8Decoder, utf8Encoder} from './utils.ts' -// @ts-ignore -if (typeof crypto !== 'undefined' && !crypto.subtle && crypto.webcrypto) { - // @ts-ignore - crypto.subtle = crypto.webcrypto.subtle -} - export const getSharedSecret = (privkey: string, pubkey: string): Uint8Array => sha256(secp256k1.getSharedSecret(privkey, '02' + pubkey).subarray(1, 33)) -export function encrypt(privkey: string, pubkey: string, text: string, v = 1) { +export function encrypt(key: Uint8Array, text: string, v = 1) { if (v !== 1) { throw new Error('NIP44: unknown encryption version') } - const key = getSharedSecret(privkey, pubkey) const nonce = randomBytes(24) const plaintext = utf8Encoder.encode(text) const ciphertext = xchacha20(key, nonce, plaintext) - return JSON.stringify({ - ciphertext: base64.encode(ciphertext), - nonce: base64.encode(nonce), - v - }) + const payload = new Uint8Array(25 + ciphertext.length) + payload.set([v], 0) + payload.set(nonce, 1) + payload.set(ciphertext, 25) + + return base64.encode(payload) } -export function decrypt(privkey: string, pubkey: string, payload: string) { +export function decrypt(key: Uint8Array, payload: string) { let data try { - data = JSON.parse(payload) as { - ciphertext: string - nonce: string - v: number - } + data = base64.decode(payload) } catch (e) { - throw new Error('NIP44: failed to parse payload') + throw new Error(`NIP44: failed to base64 decode payload: ${e}`) } - if (data.v !== 1) { - throw new Error('NIP44: unknown encryption version') + if (data[0] !== 1) { + throw new Error(`NIP44: unknown encryption version: ${data[0]}`) } - const key = getSharedSecret(privkey, pubkey) - const nonce = base64.decode(data.nonce) - const ciphertext = base64.decode(data.ciphertext) + const nonce = data.slice(1, 25) + const ciphertext = data.slice(25) const plaintext = xchacha20(key, nonce, ciphertext) return utf8Decoder.decode(plaintext)