nip04.go raw
1 package nip04
2
3 import (
4 "common/crypto/secp256k1"
5 "common/helpers"
6 "common/jsbridge/subtle"
7 )
8
9 // SharedKey derives the NIP-04 shared secret from ECDH (x-coordinate only).
10 func SharedKey(seckey, pubkey [32]byte) ([32]byte, bool) {
11 return secp256k1.ECDH(seckey, pubkey)
12 }
13
14 // Encrypt encrypts plaintext using NIP-04 (AES-256-CBC).
15 // sharedKey: 32 bytes from SharedKey.
16 // Calls fn with the encoded string "base64(ciphertext)?iv=base64(iv)".
17 func Encrypt(sharedKey [32]byte, plaintext string, fn func(string)) {
18 iv := make([]byte, 16)
19 subtle.RandomBytes(iv)
20 subtle.AESCBCEncrypt(sharedKey[:], iv, []byte(plaintext), func(ct []byte) {
21 fn(helpers.Base64Encode(ct) + "?iv=" + helpers.Base64Encode(iv))
22 })
23 }
24
25 // Decrypt decrypts a NIP-04 message "base64(ciphertext)?iv=base64(iv)".
26 // Calls fn with the plaintext.
27 func Decrypt(sharedKey [32]byte, message string, fn func(string)) {
28 // Split on "?iv=".
29 ivIdx := -1
30 for i := 0; i < len(message)-3; i++ {
31 if message[i] == '?' && message[i+1] == 'i' && message[i+2] == 'v' && message[i+3] == '=' {
32 ivIdx = i
33 break
34 }
35 }
36 if ivIdx < 0 {
37 fn("")
38 return
39 }
40 ct := helpers.Base64Decode(message[:ivIdx])
41 iv := helpers.Base64Decode(message[ivIdx+4:])
42 if ct == nil || iv == nil {
43 fn("")
44 return
45 }
46 subtle.AESCBCDecrypt(sharedKey[:], iv, ct, func(pt []byte) {
47 fn(string(pt))
48 })
49 }
50