Skip to content

Latest commit

 

History

History
53 lines (37 loc) · 3.27 KB

04.md

File metadata and controls

53 lines (37 loc) · 3.27 KB

NIP-04

暗号化されたダイレクトメッセージ

final optional author:arcbtc

暗号化されたダイレクトメッセージを指す固有のkind4は、次のような属性を持っています。

**content**は、ユーザーが書きたい文字列のbase64エンコードを送信者の秘密鍵と受診者の公開鍵を組みあわせて作られる共有暗号で暗号化したものと等しくなければなりません (MUST)。base64エンコードされた初期化ベクトルは、"iv"という名前のクエリ文字列パラメータのようにして添付されます。ここに例を示します。"content": "<encrypted_text>?iv=<initialization_vector>"

**tags**にはリレーがうまく彼らにそのイベントを転送するため、メッセージの受信者を識別するエントリを次のように格納しなけばなりません (MUST)。 ["p", "<pubkey, as a hex string>"]

**tags**には、文脈に沿った、より整理された会話ができるよう会話の中の前のメッセージや、明示的に返信しているメッセージを示すエントリを次のように含めても構いません (MAY)。["e", "<event_id>"]

メモ: ECDH実装libsecp256k1のデフォルトでは、秘密は共有点 (X座標とY座標の両方) のSHA256ハッシュです。Nostrでは、共有点のX座標のみが秘密として使用され、ハッシュ化されません。libsecp256k1を使用する場合は、X座標をコピーする関数をsecp256k1_ecdh中でhashfp引数として渡す必要が有ります。

JavaScriptでそのようなイベントを生成するためのサンプルコードはこちら。

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
}

セキュリティ上の警告

この標準はピア間の暗号化通信の最先端と考えられている物とは程遠く、加えてイベントのメタデータも流出させます。そのため本当に秘密を保ちたい用途には絶対に使用してはいけません。使用する際は、AUTHを使用してあなたのkind:4イベントを取得可能な人を制限できるリレーでのみ使用して下さい。

クライアント実装の警告

クライアントは.contentに含まれる公開鍵とノートの参照を検索して置換するべきではありません。もし通常のテキストノートのように処理 (文中の@npub...["p", "..."]タグがある#[0]で置き換える) した場合、タグは流出し、メンションされたユーザーは受信トレイにメッセージを受け取ります。