This commit is contained in:
jab-r 2025-10-08 20:53:42 -04:00 committed by GitHub
commit 325055eb96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 192 additions and 0 deletions

View File

@ -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 |

View File

@ -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: NIP17 direct messages and MLS groups. It defines:
- A normalized JSON structure for NIP17 DMs (keys live only inside the DM ciphertext)
- An MLS profile that derives perattachment AEAD key/nonce via the MLS exporter
- A perattachment AEAD scheme (AES256GCM) with normative sizes
- Integrity requirements (SHA256 over ciphertext)
- HTTP storage guidance (presigned upload/finalize), optionally compatible with NIP96 and NIP98
Public, unencrypted tags (attach/eattach) are explicitly out of scope for this profile.
## Motivation
Clients and servers need a consistent, interoperable, privacypreserving mechanism for sharing files in private contexts. This document scopes the solution to encryptedonly delivery via NIP17 (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 relayvisible metadata.
- Use perattachment 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 offrelay at canonical HTTPS URLs.
## Definitions
- **Attachment**: A binary resource referenced by a message.
- **Ciphertext attachment**: Uploaded bytes are encrypted; clients decrypt locally to render.
- **Perattachment key**: A random 32byte AES256 key generated uniquely per attachment (DMs). For MLS, the key is derived via the exporter.
## Specification
### 1. Cipher and integrity
- AEAD: AES256GCM
- 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. NIP17 direct messages (DMs)
Attachment parameters MUST live inside the DMs 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 NIP17.
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 rerendering.
### 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 relayvisible 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 messagescoped `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).
- NIP92 “imeta” and NIP94 filemetadata records for public media.
This profile targets encrypted attachments delivered via NIP17 and MLS only.
### 5. Storage and transport
- Storage: Offrelay HTTP object storage with presigned upload + finalize flows that return canonical download URLs and servercomputed metadata (size/checksum). These flows are compatible with NIP96 where applicable.
- Auth: Publishers and storage providers MAY require NIP98 (HTTP Auth) for upload/finalize/download.
- Alternate device transports (e.g., BLE/Noise) MAY carry the same JSON payloads; this does not change the onwire 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 safecontent policies when fetching.
### 7. Security considerations
- Do not place keys, IVs, or tags in public tags or content.
- Do not include encryption material in NIP92 `imeta` or any relayvisible metadata.
- Treat URLbased key delivery or external key references as nonconfidential; this profile forbids such patterns.
- Ensure unique IVs per key; perattachment keys simplify this, but libraries MUST still generate fresh IVs.
## Examples
### NIP17 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: **loxationsw**
- Supports perattachment AES256GCM, presigned upload/finalize, NIP17 DM JSON payloads, and UI rendering.
- MLS exporterbased attachments are supported in the MLS messaging flows used by Loxation.