remove browserify-cipher, use crypto.subtle for nip04.

This commit is contained in:
fiatjaf 2022-12-21 16:04:00 -03:00
parent 0500415a4e
commit 41a1614d89
No known key found for this signature in database
GPG Key ID: BAD43C4BE5C1A3A1
7 changed files with 58 additions and 35 deletions

View File

@ -24,6 +24,7 @@
"document": false, "document": false,
"navigator": false, "navigator": false,
"window": false, "window": false,
"crypto": false,
"location": false, "location": false,
"URL": false, "URL": false,
"URLSearchParams": false, "URLSearchParams": false,

View File

@ -171,7 +171,7 @@ let pk2 = getPublicKey(sk2)
// on the sender side // on the sender side
let message = 'hello' let message = 'hello'
let ciphertext = nip04.encrypt(sk1, pk2, 'hello') let ciphertext = await nip04.encrypt(sk1, pk2, 'hello')
let event = { let event = {
kind: 4, kind: 4,
@ -187,7 +187,7 @@ sendEvent(event)
sub.on('event', (event) => { sub.on('event', (event) => {
let sender = event.tags.find(([k, v]) => k === 'p' && && v && v !== '')[1] let sender = event.tags.find(([k, v]) => k === 'p' && && v && v !== '')[1]
pk1 === sender pk1 === sender
let plaintext = nip04.decrypt(sk2, pk1, event.content) let plaintext = await nip04.decrypt(sk2, pk1, event.content)
}) })
``` ```

View File

@ -2,13 +2,13 @@
const {nip04, getPublicKey, generatePrivateKey} = require('./lib/nostr.cjs') const {nip04, getPublicKey, generatePrivateKey} = require('./lib/nostr.cjs')
test('encrypt and decrypt message', () => { test('encrypt and decrypt message', async () => {
let sk1 = generatePrivateKey() let sk1 = generatePrivateKey()
let sk2 = generatePrivateKey() let sk2 = generatePrivateKey()
let pk1 = getPublicKey(sk1) let pk1 = getPublicKey(sk1)
let pk2 = getPublicKey(sk2) let pk2 = getPublicKey(sk2)
expect(nip04.decrypt(sk2, pk1, nip04.encrypt(sk1, pk2, 'hello'))).toEqual( expect(
'hello' await nip04.decrypt(sk2, pk1, await nip04.encrypt(sk1, pk2, 'hello'))
) ).toEqual('hello')
}) })

View File

@ -1,45 +1,66 @@
import {Buffer} from 'buffer'
import {randomBytes} from '@noble/hashes/utils' import {randomBytes} from '@noble/hashes/utils'
import * as secp256k1 from '@noble/secp256k1' import * as secp256k1 from '@noble/secp256k1'
// @ts-ignore import {encode as b64encode, decode as b64decode} from 'base64-arraybuffer'
import aes from 'browserify-cipher'
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<string> {
const key = secp256k1.getSharedSecret(privkey, '02' + pubkey) const key = secp256k1.getSharedSecret(privkey, '02' + pubkey)
const normalizedKey = getNormalizedX(key) const normalizedKey = getNormalizedX(key)
let iv = Uint8Array.from(randomBytes(16)) let iv = Uint8Array.from(randomBytes(16))
var cipher = aes.createCipheriv( let plaintext = utf8Encoder.encode(text)
'aes-256-cbc', let cryptoKey = await crypto.subtle.importKey(
Buffer.from(normalizedKey, 'hex'), 'raw',
iv normalizedKey,
{name: 'AES-CBC'},
false,
['encrypt']
) )
let encryptedMessage = cipher.update(text, 'utf8', 'base64') let ciphertext = await crypto.subtle.encrypt(
encryptedMessage += cipher.final('base64') {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, privkey: string,
pubkey: string, pubkey: string,
ciphertext: string data: string
): string { ): Promise<string> {
let [cip, iv] = ciphertext.split('?iv=') let [ctb64, ivb64] = data.split('?iv=')
let key = secp256k1.getSharedSecret(privkey, '02' + pubkey) let key = secp256k1.getSharedSecret(privkey, '02' + pubkey)
let normalizedKey = getNormalizedX(key) let normalizedKey = getNormalizedX(key)
var decipher = aes.createDecipheriv( let cryptoKey = await crypto.subtle.importKey(
'aes-256-cbc', 'raw',
Buffer.from(normalizedKey, 'hex'), normalizedKey,
Buffer.from(iv, 'base64') {name: 'AES-CBC'},
false,
['decrypt']
) )
let decryptedMessage = decipher.update(cip, 'base64', 'utf8') let ciphertext = b64decode(ctb64)
decryptedMessage += decipher.final('utf8') 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 { function getNormalizedX(key: Uint8Array): Uint8Array {
return Buffer.from(key.slice(1, 33)).toString('hex') return key.slice(1, 33)
} }

View File

@ -1,6 +1,8 @@
import * as secp256k1 from '@noble/secp256k1' import * as secp256k1 from '@noble/secp256k1'
import {bech32} from 'bech32' import {bech32} from 'bech32'
import {utf8Decoder, utf8Encoder} from './utils'
export type ProfilePointer = { export type ProfilePointer = {
pubkey: string // hex pubkey: string // hex
relays?: string[] relays?: string[]
@ -11,9 +13,6 @@ export type EventPointer = {
relays?: string[] relays?: string[]
} }
let utf8Decoder = new TextDecoder('utf-8')
let utf8Encoder = new TextEncoder()
export function decode(nip19: string): { export function decode(nip19: string): {
type: string type: string
data: ProfilePointer | EventPointer | string data: ProfilePointer | EventPointer | string

View File

@ -13,9 +13,9 @@
"@noble/secp256k1": "^1.7.0", "@noble/secp256k1": "^1.7.0",
"@scure/bip32": "^1.1.1", "@scure/bip32": "^1.1.1",
"@scure/bip39": "^1.1.0", "@scure/bip39": "^1.1.0",
"base64-arraybuffer": "^1.0.2",
"bech32": "^2.0.0", "bech32": "^2.0.0",
"browserify-cipher": ">=1", "readable-stream": "^4.2.0",
"buffer": "^6.0.3",
"websocket-polyfill": "^0.0.3" "websocket-polyfill": "^0.0.3"
}, },
"keywords": [ "keywords": [

2
utils.ts Normal file
View File

@ -0,0 +1,2 @@
export const utf8Decoder = new TextDecoder('utf-8')
export const utf8Encoder = new TextEncoder()