From 41a1614d898b5e6d231ff853119d9b8b191a7d6f Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Wed, 21 Dec 2022 16:04:00 -0300 Subject: [PATCH] remove browserify-cipher, use crypto.subtle for nip04. --- .eslintrc.json | 1 + README.md | 4 +-- nip04.test.js | 8 +++--- nip04.ts | 69 ++++++++++++++++++++++++++++++++------------------ nip19.ts | 5 ++-- package.json | 4 +-- utils.ts | 2 ++ 7 files changed, 58 insertions(+), 35 deletions(-) create mode 100644 utils.ts diff --git a/.eslintrc.json b/.eslintrc.json index 3954f0d..32a0311 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -24,6 +24,7 @@ "document": false, "navigator": false, "window": false, + "crypto": false, "location": false, "URL": false, "URLSearchParams": false, diff --git a/README.md b/README.md index 48a0be9..373e833 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ let pk2 = getPublicKey(sk2) // on the sender side let message = 'hello' -let ciphertext = nip04.encrypt(sk1, pk2, 'hello') +let ciphertext = await nip04.encrypt(sk1, pk2, 'hello') let event = { kind: 4, @@ -187,7 +187,7 @@ sendEvent(event) sub.on('event', (event) => { let sender = event.tags.find(([k, v]) => k === 'p' && && v && v !== '')[1] pk1 === sender - let plaintext = nip04.decrypt(sk2, pk1, event.content) + let plaintext = await nip04.decrypt(sk2, pk1, event.content) }) ``` diff --git a/nip04.test.js b/nip04.test.js index 581f7a3..90a4380 100644 --- a/nip04.test.js +++ b/nip04.test.js @@ -2,13 +2,13 @@ const {nip04, getPublicKey, generatePrivateKey} = require('./lib/nostr.cjs') -test('encrypt and decrypt message', () => { +test('encrypt and decrypt message', async () => { let sk1 = generatePrivateKey() let sk2 = generatePrivateKey() let pk1 = getPublicKey(sk1) let pk2 = getPublicKey(sk2) - expect(nip04.decrypt(sk2, pk1, nip04.encrypt(sk1, pk2, 'hello'))).toEqual( - 'hello' - ) + expect( + await nip04.decrypt(sk2, pk1, await nip04.encrypt(sk1, pk2, 'hello')) + ).toEqual('hello') }) diff --git a/nip04.ts b/nip04.ts index 5e069ce..34b6655 100644 --- a/nip04.ts +++ b/nip04.ts @@ -1,45 +1,66 @@ -import {Buffer} from 'buffer' import {randomBytes} from '@noble/hashes/utils' import * as secp256k1 from '@noble/secp256k1' -// @ts-ignore -import aes from 'browserify-cipher' +import {encode as b64encode, decode as b64decode} from 'base64-arraybuffer' -export function encrypt(privkey: string, pubkey: string, text: string): string { +import {utf8Decoder, utf8Encoder} from './utils' + +export async function encrypt( + privkey: string, + pubkey: string, + text: string +): Promise { const key = secp256k1.getSharedSecret(privkey, '02' + pubkey) const normalizedKey = getNormalizedX(key) let iv = Uint8Array.from(randomBytes(16)) - var cipher = aes.createCipheriv( - 'aes-256-cbc', - Buffer.from(normalizedKey, 'hex'), - iv + let plaintext = utf8Encoder.encode(text) + let cryptoKey = await crypto.subtle.importKey( + 'raw', + normalizedKey, + {name: 'AES-CBC'}, + false, + ['encrypt'] ) - let encryptedMessage = cipher.update(text, 'utf8', 'base64') - encryptedMessage += cipher.final('base64') + let ciphertext = await crypto.subtle.encrypt( + {name: 'AES-CBC', iv}, + cryptoKey, + plaintext + ) + let ctb64 = b64encode(ciphertext) + let ivb64 = b64encode(iv.buffer) - return `${encryptedMessage}?iv=${Buffer.from(iv.buffer).toString('base64')}` + return `${ctb64}?iv=${ivb64}` } -export function decrypt( +export async function decrypt( privkey: string, pubkey: string, - ciphertext: string -): string { - let [cip, iv] = ciphertext.split('?iv=') + data: string +): Promise { + let [ctb64, ivb64] = data.split('?iv=') let key = secp256k1.getSharedSecret(privkey, '02' + pubkey) let normalizedKey = getNormalizedX(key) - var decipher = aes.createDecipheriv( - 'aes-256-cbc', - Buffer.from(normalizedKey, 'hex'), - Buffer.from(iv, 'base64') + let cryptoKey = await crypto.subtle.importKey( + 'raw', + normalizedKey, + {name: 'AES-CBC'}, + false, + ['decrypt'] ) - let decryptedMessage = decipher.update(cip, 'base64', 'utf8') - decryptedMessage += decipher.final('utf8') + let ciphertext = b64decode(ctb64) + let iv = b64decode(ivb64) - return decryptedMessage + let plaintext = await crypto.subtle.decrypt( + {name: 'AES-CBC', iv}, + cryptoKey, + ciphertext + ) + + let text = utf8Decoder.decode(plaintext) + return text } -function getNormalizedX(key: Uint8Array): string { - return Buffer.from(key.slice(1, 33)).toString('hex') +function getNormalizedX(key: Uint8Array): Uint8Array { + return key.slice(1, 33) } diff --git a/nip19.ts b/nip19.ts index c4cbad2..e545a59 100644 --- a/nip19.ts +++ b/nip19.ts @@ -1,6 +1,8 @@ import * as secp256k1 from '@noble/secp256k1' import {bech32} from 'bech32' +import {utf8Decoder, utf8Encoder} from './utils' + export type ProfilePointer = { pubkey: string // hex relays?: string[] @@ -11,9 +13,6 @@ export type EventPointer = { relays?: string[] } -let utf8Decoder = new TextDecoder('utf-8') -let utf8Encoder = new TextEncoder() - export function decode(nip19: string): { type: string data: ProfilePointer | EventPointer | string diff --git a/package.json b/package.json index bc9a91b..1511012 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,9 @@ "@noble/secp256k1": "^1.7.0", "@scure/bip32": "^1.1.1", "@scure/bip39": "^1.1.0", + "base64-arraybuffer": "^1.0.2", "bech32": "^2.0.0", - "browserify-cipher": ">=1", - "buffer": "^6.0.3", + "readable-stream": "^4.2.0", "websocket-polyfill": "^0.0.3" }, "keywords": [ diff --git a/utils.ts b/utils.ts new file mode 100644 index 0000000..784a868 --- /dev/null +++ b/utils.ts @@ -0,0 +1,2 @@ +export const utf8Decoder = new TextDecoder('utf-8') +export const utf8Encoder = new TextEncoder()