nip44 updates (#278)

Co-authored-by: Jonathan Staab <shtaab@gmail.com>
This commit is contained in:
Jon Staab 2023-08-16 09:53:37 -07:00 committed by GitHub
parent 2431896921
commit b92407b156
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 29 deletions

View File

@ -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')
})

View File

@ -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)