Merge 7c8a9170c3
into 2ace01cf1a
This commit is contained in:
commit
cb4736c9f8
|
@ -107,6 +107,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
|||
- [NIP-C0: Code Snippets](C0.md)
|
||||
- [NIP-C7: Chats](C7.md)
|
||||
- [NIP-EE: E2EE Messaging using MLS Protocol](EE.md)
|
||||
- [NIP-XXX: Encrypted Binary Attachments | DRAFT](nip-xxx-binary-attachments.md)
|
||||
|
||||
## Event Kinds
|
||||
| kind | description | NIP |
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
---
|
||||
nip: XXX
|
||||
title: Encrypted Binary Attachments for DMs and MLS
|
||||
author: Jonathan Borden (jonathan@loxation.com)
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
created: 2025-08-23
|
||||
license: CC0-1.0
|
||||
---
|
||||
|
||||
## Abstract
|
||||
|
||||
This NIP profile standardizes encrypted binary attachments (images, audio, video, documents) for private Nostr messaging only: NIP‑17 direct messages and MLS groups. It defines:
|
||||
|
||||
- A normalized JSON structure for NIP‑17 DMs (keys live only inside the DM ciphertext)
|
||||
- An MLS profile that derives per‑attachment AEAD key/nonce via the MLS exporter
|
||||
- A per‑attachment AEAD scheme (AES‑256‑GCM) with normative sizes
|
||||
- Integrity requirements (SHA‑256 over ciphertext)
|
||||
- HTTP storage guidance (presigned upload/finalize), optionally compatible with NIP‑96 and NIP‑98
|
||||
|
||||
Public, unencrypted tags (attach/eattach) are explicitly out of scope for this profile.
|
||||
|
||||
## Motivation
|
||||
|
||||
Clients and servers need a consistent, interoperable, privacy‑preserving mechanism for sharing files in private contexts. This document scopes the solution to encrypted‑only delivery via NIP‑17 (1:1) and MLS (1:group), which matches our deployment and avoids ambiguity and leakage associated with public note tags.
|
||||
|
||||
## Rationale
|
||||
|
||||
- Keep symmetric keys in encrypted channels only (DM content or MLS exporter). Never in public tags or relay‑visible metadata.
|
||||
- Use per‑attachment AEAD to avoid key reuse and enable granular sharing and revocation.
|
||||
- Compute integrity over ciphertext so clients can verify prior to decryption and rendering.
|
||||
- Keep events lightweight; store bytes off‑relay at canonical HTTPS URLs.
|
||||
|
||||
## Definitions
|
||||
|
||||
- **Attachment**: A binary resource referenced by a message.
|
||||
- **Ciphertext attachment**: Uploaded bytes are encrypted; clients decrypt locally to render.
|
||||
- **Per‑attachment key**: A random 32‑byte AES‑256 key generated uniquely per attachment (DMs). For MLS, the key is derived via the exporter.
|
||||
|
||||
## Specification
|
||||
|
||||
### 1. Cipher and integrity
|
||||
|
||||
- AEAD: AES‑256‑GCM
|
||||
- key: 32 bytes (base64) [DMs only; MLS derives]
|
||||
- iv/nonce: 12 bytes (base64)
|
||||
- tag: 16 bytes (base64)
|
||||
- Integrity: sha256 MUST be computed over ciphertext and verified before decrypt/render.
|
||||
|
||||
### 2. NIP‑17 direct messages (DMs)
|
||||
|
||||
Attachment parameters MUST live inside the DM’s encrypted content (not tags). The DM plaintext embeds a normalized JSON array of attachment objects:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "message",
|
||||
"text": "optional user text",
|
||||
"attachments": [
|
||||
{
|
||||
"url": "https://storage.example/enc/blob",
|
||||
"ct": "image/jpeg",
|
||||
"size": 23011,
|
||||
"sha256": "<hex_of_ciphertext>",
|
||||
"fn": "photo.jpg",
|
||||
"enc": {
|
||||
"mode": "dm",
|
||||
"algo": "A256GCM",
|
||||
"k": "<b64-32-bytes>",
|
||||
"iv": "<b64-12-bytes>",
|
||||
"t": "<b64-16-bytes>"
|
||||
},
|
||||
"alt": "a cat",
|
||||
"blurhash": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Receiver processing:
|
||||
1) Decrypt the DM per NIP‑17.
|
||||
2) Fetch the ciphertext bytes from `url`.
|
||||
3) Verify `sha256` over ciphertext.
|
||||
4) Decrypt with `enc.k/iv/t`.
|
||||
5) Render using `ct`, `fn`, `alt`, and optional hints (e.g., `blurhash`).
|
||||
|
||||
Notes:
|
||||
- The `size` field SHOULD reflect ciphertext length.
|
||||
- Clients SHOULD cache both ciphertext and decrypted plaintext for efficient re‑rendering.
|
||||
|
||||
### 3. MLS group attachments
|
||||
|
||||
For MLS application messages, the attachment AEAD key and nonce are derived via the MLS exporter; no symmetric key material is placed in relay‑visible metadata.
|
||||
|
||||
Key/nonce derivation (normative):
|
||||
- key = MLS.exporter(label="attachment", context=concat(epoch, "|", ctx), length=32)
|
||||
- nonce = MLS.exporter(label="attachment-nonce", context=concat(epoch, "|", ctx), length=12)
|
||||
|
||||
Where `ctx` is a stable, mutually known identifier for this attachment (e.g., server `blobId` or a message‑scoped `attachmentId`). Publishers MUST include enough metadata for receivers to compute the same `ctx`.
|
||||
|
||||
Attachment metadata embedded in or adjacent to the MLS application message SHOULD include:
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://storage.example/enc/blob",
|
||||
"ct": "image/jpeg",
|
||||
"size": 23011,
|
||||
"sha256": "<hex_of_ciphertext>",
|
||||
"fn": "photo.jpg",
|
||||
"enc": {
|
||||
"mode": "mls",
|
||||
"algo": "A256GCM",
|
||||
"t": "<b64-16-bytes>",
|
||||
"mls": { "group_id": "<groupId>", "epoch": 42, "ctx": "<blobId|attachmentId>" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Receiver processing:
|
||||
1) Use MLS state for `group_id`/`epoch` to derive key and nonce with the exporter and `ctx`.
|
||||
2) Fetch ciphertext, verify `sha256`, then decrypt with derived key/nonce and verify auth tag `t`.
|
||||
|
||||
### 4. Out of scope
|
||||
|
||||
- Public note tags for unencrypted or encrypted media (attach/eattach).
|
||||
- NIP‑92 “imeta” and NIP‑94 file‑metadata records for public media.
|
||||
This profile targets encrypted attachments delivered via NIP‑17 and MLS only.
|
||||
|
||||
### 5. Storage and transport
|
||||
|
||||
- Storage: Off‑relay HTTP object storage with presigned upload + finalize flows that return canonical download URLs and server‑computed metadata (size/checksum). These flows are compatible with NIP‑96 where applicable.
|
||||
- Auth: Publishers and storage providers MAY require NIP‑98 (HTTP Auth) for upload/finalize/download.
|
||||
- Alternate device transports (e.g., BLE/Noise) MAY carry the same JSON payloads; this does not change the on‑wire format for Nostr DMs or MLS.
|
||||
|
||||
### 6. Client behavior
|
||||
|
||||
- Verify `sha256` over ciphertext before decrypt/render.
|
||||
- Verify GCM auth tag during decryption.
|
||||
- Show filename/thumbnail; respect accessibility fields like `alt`.
|
||||
- Cache intelligently; apply quotas and safe‑content policies when fetching.
|
||||
|
||||
### 7. Security considerations
|
||||
|
||||
- Do not place keys, IVs, or tags in public tags or content.
|
||||
- Do not include encryption material in NIP‑92 `imeta` or any relay‑visible metadata.
|
||||
- Treat URL‑based key delivery or external key references as non‑confidential; this profile forbids such patterns.
|
||||
- Ensure unique IVs per key; per‑attachment keys simplify this, but libraries MUST still generate fresh IVs.
|
||||
|
||||
## Examples
|
||||
|
||||
### NIP‑17 DM with encrypted attachment
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "message",
|
||||
"attachments": [
|
||||
{
|
||||
"url": "https://cdn.example/enc/xyz",
|
||||
"ct": "image/jpeg",
|
||||
"size": 23011,
|
||||
"sha256": "55aa...",
|
||||
"fn": "photo.jpg",
|
||||
"enc": { "mode": "dm", "algo": "A256GCM", "k": "...", "iv": "...", "t": "..." }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### MLS attachment metadata (ciphertext at URL; key/nonce via exporter)
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "https://cdn.example/enc/xyz",
|
||||
"ct": "video/mp4",
|
||||
"size": 8329001,
|
||||
"sha256": "2f3a...",
|
||||
"fn": "talk.mp4",
|
||||
"enc": {
|
||||
"mode": "mls",
|
||||
"algo": "A256GCM",
|
||||
"t": "....",
|
||||
"mls": { "group_id": "deadbeef", "epoch": 42, "ctx": "blob:e3b0c442..." }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Status
|
||||
|
||||
- Reference client: **loxation‑sw**
|
||||
- Supports per‑attachment AES‑256‑GCM, presigned upload/finalize, NIP‑17 DM JSON payloads, and UI rendering.
|
||||
- MLS exporter‑based attachments are supported in the MLS messaging flows used by Loxation.
|
||||
|
Loading…
Reference in New Issue