NIP-04

O nip 4 define o funcionamento das mensagens diretas criptografadas (kind 4).
NIP-04

Mensagem Direta Criptografada

final unrecommended optional

Um evento especial com o kind 4, que significa “mensagem direta criptografada”. Ele deve possuir os seguintes atributos:

content

DEVE ser igual a uma string criptografada com AES-256-CBC, codificada em base64, contendo qualquer texto que o usuário queira escrever.

Essa criptografia deve ser feita usando um cifra compartilhada, gerada pela combinação da chave pública do destinatário com a chave privada do remetente.

O conteúdo criptografado deve ser concatenado com o vetor de inicialização (IV), também codificado em base64, como se fosse um parâmetro de query string chamado "iv".

O formato deve ser o seguinte:

"content": "<texto_criptografado>?iv=<vetor_de_inicializacao>"

tags

DEVE conter uma entrada identificando o destinatário da mensagem (para que os relays possam encaminhar naturalmente esse evento a ele), no formato:

["p", "<chave_publica_em_hexadecimal>"]

tags (opcional)

PODE conter uma entrada identificando a mensagem anterior de uma conversa ou uma mensagem específica à qual estamos respondendo (permitindo conversas mais organizadas e contextuais), no formato:

["e", "<event_id>"]

Nota

Por padrão, na implementação ECDH da biblioteca libsecp256k1, o segredo é o hash SHA256 do ponto compartilhado (incluindo as coordenadas X e Y).

No Nostr, apenas a coordenada X do ponto compartilhado é usada como segredo, e ela NÃO é hasheada.

Ao usar a libsecp256k1, uma função personalizada que copie apenas a coordenada X deve ser passada como argumento hashfp na função secp256k1_ecdh. Veja aqui.

Exemplo de código em JavaScript para gerar esse evento:

import crypto from 'crypto'
import * as secp from '@noble/secp256k1'

let sharedPoint = secp.getSharedSecret(ourPrivateKey, '02' + theirPublicKey)
let sharedX = sharedPoint.slice(1, 33)

let iv = crypto.randomFillSync(new Uint8Array(16))
var cipher = crypto.createCipheriv(
  'aes-256-cbc',
  Buffer.from(sharedX),
  iv
)
let encryptedMessage = cipher.update(text, 'utf8', 'base64')
encryptedMessage += cipher.final('base64')
let ivBase64 = Buffer.from(iv.buffer).toString('base64')

let event = {
  pubkey: ourPubKey,
  created_at: Math.floor(Date.now() / 1000),
  kind: 4,
  tags: [['p', theirPublicKey]],
  content: encryptedMessage + '?iv=' + ivBase64
}

⚠️ Aviso de Segurança

Este padrão não chega nem perto do que é considerado o estado da arte em comunicação criptografada entre pares e vaza metadados nos eventos.

Portanto, não deve ser usado para nada que realmente precise ser mantido em segredo, e somente com relays que utilizem AUTH para restringir quem pode buscar seus eventos de kind:4.

⚠️ Aviso para Implementação em Clientes

Clientes não devem procurar e substituir referências a chaves públicas ou notas dentro do .content.

Se o conteúdo for processado como uma nota de texto comum (onde @npub... é substituído por #[0] com uma tag ["p", "..."]), essas tags serão vazadas e o usuário mencionado receberá a mensagem na caixa de entrada.


No comments yet.