NIP-44
暗号化アルゴリズムをバージョンを管理できるようにするNIP-04(Encrypted Direct Message) の代替案。 この仕様は暗号化方式のみを定義しており、DMのkind等は定義しない。
特長
暗号の強化: NIP-04の欠点を解消し、パディングオラクル攻撃からの耐性を向上する。
コンテンツとタグの構造: イベントには、バージョン、nonce、暗号文などの属性が含まれるべきで、タグには受信者や返信先の情報が入る。
バージョン管理: クライアントはサポートしていないバージョンのメッセージを受信するとエラーを返し、ユーザーに対応するためのアクションを提案する。
/icons/hr.icon
策定中段階の古い翻訳
Lists
1. 暗号の強化: NIP4の欠点を解消し、パディングオラクル攻撃からの耐性を向上する。
2. 新しいイベント: kind: 44で、暗号化されたダイレクトメッセージということを示す。
3. コンテンツとタグの構造: イベントには、バージョン、nonce、暗号文などの属性が含まれるべきで、タグには受信者や返信先の情報が入る。
4. メタデータの漏洩を防ぐ: クライアントは特定のフローを実装する必要があり、認証とNIP-65の使用を通じて、メタデータの漏洩を抑制できる。 5. バージョン管理: クライアントはサポートしていないバージョンのメッセージを受信するとエラーを返し、ユーザーに対応するためのアクションを提案する。
このNIPは、暗号化アルゴリズムの選択が不可能な NIP-04(パディング オラクル攻撃に対して潜在的に脆弱であり、ランダムなキーと区別できないキーを使用している)を置き換え、暗号化のバージョン管理を導入することを目的としている。 kind:44の特別なイベントは、「暗号化されたダイレクト メッセージ」を意味し、このイベントでは、次のような属性を持つことが想定されている。
content はCSV形式 v,param1,param2... で記述されている必要があります。バージョンが異なるとパラメーター数が異なる場合があります。最初の部分は常に数値型の暗号化アルゴリズムのバージョンです。(MUST)
Version: 1のパラメーター
1. nonce: base64でエンコードされたxchachaアルゴリズムのnonce値
2. ciphertext: plaintext に対して (key, nonce) から作成された、base64 でエンコードされた xchacha暗号文(例:1,3dBKd83Pg2Q4Tu2A2e8N++c+ZW2IBc2f,FvQi1H4atMwU+FzUR/0CJ7kowjs+)
tags には ["p", "<pubkey, as a hex string>"] の形式で、メッセージの受信者の識別子(リレーがこのイベントを自然に転送できるように) が含まれている必要がある。(MUST)
tags には ["e", "<event_id>"] の形式で、会話内の前のメッセージの識別子、または明示的に返信しているメッセージ (状況に応じて、より組織化された会話が発生する可能性があります) を含めることができる。(MAY)
注: libsecp256k1 ECDH 実装のデフォルトでは、シークレットは共有ポイントの SHA256 ハッシュ (X 座標と Y 座標の両方) である。NIP-4では、ハッシュ化されていない共有ポイントが使用されていないが、このNIPでは正確な実装を使用している。 メタデータの漏洩
すべての nostr イベントはインターネット経由で渡されるため、一部のメタデータは常に漏洩する可能性がある。
互換性のあるすべてのクライアントは、メタデータの漏洩を防ぐために次のフローを実装する必要がある。
1. アリスは、NIP-42 を使用して wss://nostr.example.com で認証する。これは、メッセージの送受信ができるのは、適切な認証されたユーザーのみであることを意味する。 2. 成功すると、アリスは優先リレーとして wss://nostr.example.com を指定して NIP-65 イベントを作成します。設定はパブリックであり、ネットワークはアリスの優先 DM リレーを認識します。
ユーザーが NIP-65 優先リレーを指定しなかった場合、ダイレクト メッセージを受信すべきではない。 (SHOULD NOT)
バージョン管理
クライアントは、サポートしていないバージョンの NIP44 メッセージを受信した場合、説明的なエラーを返す必要がある。エラーは、メッセージのバージョンがサポートされていないことを示し、アップグレードや別のクライアントへの切り替えなどの適切なアクションを提案する必要がある。 (MUST)
現在定義されている暗号化アルゴリズム:
0x00 - 予約済み
0x01 - 会話ごとに同じキー sha256(ecdh) を持つXChaCha
セキュリティに関する警告
この標準は、ピア間の暗号化通信において最先端と考えられているものには程遠いものであり、イベント内のメタデータが漏洩するため、本当に機密にする必要があるものには使用できない。また、kind:4 イベントを取得できるユーザーを制限するために AUTH を使用するリレーでのみ使用すべきである。
クライアント実装に関する警告
クライアントは、 .content から公開キーやメモ参照を検索および置換してはならない。通常のテキスト メモのように処理すると ( @npub... が ["p", "..."] タグを持つ #[0] に置き換えられてしまう)、タグが漏洩し、言及されたユーザーにはメッセージを送信すべき。
アルゴリズム
code: (tsx)
// npm install @noble/curves @noble/hashes @scure/base @stablelib/xchacha20
import {xchacha20} from '@noble/ciphers/chacha'
import {secp256k1} from '@noble/curves/secp256k1'
import {sha256} from '@noble/hashes/sha256'
import {randomBytes} from '@noble/hashes/utils'
import {base64} from '@scure/base'
import {utf8Decoder, utf8Encoder} from './utils.ts'
export function getConversationKey(privkeyA: string, pubkeyB: string): Uint8Array {
const key = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB)
return sha256(key.subarray(1, 33))
}
export function encrypt(
key: Uint8Array,
text: string,
ver = 1
): string {
if (ver !== 1) throw new Error('NIP44: unknown encryption version')
let nonce = randomBytes(24)
let plaintext = utf8Encoder.encode(text)
let ciphertext = xchacha20(key, nonce, plaintext, plaintext)
return 1,${base64.encode(nonce)},${base64.encode(ciphertext)}
}
export function decrypt(key: Uint8Array, data: string): string {
let dt = data.split(',')
if (dt.length !== 3) throw new Error('NIP44: unknown encryption version');
let v = Number.parseInt(dt0) if (v !== 1) throw new Error('NIP44: unknown encryption version')
let nonce = base64.decode(dt1) let ciphertext = base64.decode(dt2) let plaintext = xchacha20(key, nonce, ciphertext)
let text = utf8Decoder.decode(plaintext)
return text
}