<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
<!-- NERF is a trademark of defconxt. -->

# Privacy, Cryptography & Self-Hosting Security -- Deep Training Notes

Extracted 2026-03-14 from source repos and documentation.
Sources: cryptomator-develop, ente-main, yopass-master, imgcrypt-main, invidious-master,
dns-blocklists-main, Betterfox-main, plus web references.

---

## 1. Cryptomator -- Transparent Cloud File Encryption

### Vault Format (v8)

Configuration stored in `vault.cryptomator` (signed JWT). Contains `cipherCombo` field
(`SIV_GCM` or `SIV_CTRMAC`) and shortening threshold.

### Key Derivation

| Parameter | Value |
|-----------|-------|
| Algorithm | scrypt (non-parallel) |
| Output | 32 bytes (Key Encryption Key) |
| scryptCostParam (N) | 32768 |
| scryptBlockSize (r) | 8 |
| Salt | Random, Base64-encoded, stored in `masterkey.cryptomator` |

### Masterkey Structure

Two independent 256-bit keys generated via CSPRNG:
- **Encryption masterkey** -- file content and name encryption
- **MAC masterkey** -- authentication

Both wrapped with AES Key Wrap (RFC 3394) using the scrypt-derived KEK. Stored
in `masterkey.cryptomator`.

### Recovery Key

- 64-byte raw masterkey + 2-byte CRC32 checksum = 66 bytes
- Encoded as BIP39-style word sequence via `WordEncoder`
- CRC32 of rawKey, truncated to 16 most significant bits, appended before encoding
- Key zeroization enforced (`Arrays.fill(rawKey, (byte) 0x00)`)

### File Header (68 bytes)

```
[12B nonce] [40B AES-GCM encrypted payload] [16B GCM tag]
                  |
                  +-- 8B filler (0xFFFFFFFFFFFFFFFF)
                  +-- 32B file content key (random per file)
```

### File Content Encryption (AES-256-GCM)

- Chunk size: 32 KiB plaintext -> 32 KiB + 28 bytes ciphertext
- Per-chunk structure: `[12B nonce] [up to 32 KiB encrypted] [16B GCM tag]`
- AAD per chunk: `chunk_number (64-bit BE) || header_nonce`
- Chunk numbering prevents reordering/truncation attacks

### Filename Encryption (AES-SIV)

- Input: UTF-8 NFC-normalized filename
- Associated data: parent directory ID (prevents undetected move between dirs)
- Output: Base64URL-encoded + `.c9r` extension
- Long names (>220 chars encoded): SHA-1 hash + `.c9s` extension (compatibility)

### Directory ID Encryption

- Root directory ID: empty string
- Other directories: random string up to 36 ASCII chars
- Encrypted with AES-SIV, then SHA-1 hashed, then Base32-encoded for path

### Security Properties

- Each file self-contained (no shared metadata = no single point of failure)
- Authenticated encryption detects tampering before decryption
- File-per-file independent keys; compromise of one file key does not affect others
- Cloud provider sees only encrypted blobs with obfuscated directory structure

---

## 2. Ente -- End-to-End Encrypted Photo/File Storage

### Algorithm Suite

| Operation | Algorithm | Library |
|-----------|-----------|---------|
| Key Exchange | X25519 ECDH | libsodium / CryptoKit |
| Symmetric (keys/tokens) | XSalsa20-Poly1305 (secretbox) | libsodium |
| Symmetric (files) | XChaCha20-Poly1305 (secretstream) | libsodium |
| Anonymous encryption | X25519 + XSalsa20-Poly1305 (sealed box) | libsodium |
| Hashing | BLAKE2b (64-byte / 512-bit output) | libsodium |
| Password KDF | Argon2id | libsodium / platform-specific |
| Authentication | SRP (4096-bit, SHA-256, generator 5, RFC 5054) | custom |

### Argon2id Parameters

| Mode | Memory Limit | Ops Limit | Output |
|------|-------------|-----------|--------|
| Interactive | 64 MB | 2 | 32 bytes |
| Sensitive | 1 GB | 4 | 32 bytes |
| Salt size | 16 bytes | -- | -- |

### Key Constants

| Constant | Value |
|----------|-------|
| KEY_BYTES | 32 |
| NONCE_BYTES (secretbox) | 24 |
| HEADER_BYTES (stream/blob) | 24 |
| SALT_BYTES | 16 |
| SEAL_OVERHEAD | 48 (32B ephemeral_pk + 16B MAC) |
| ENCRYPTION_CHUNK_SIZE | 4 MiB (4,194,304 bytes) |
| Per-chunk overhead (stream) | 17 bytes |
| Cipher chunk size | 4,194,321 bytes |

### Wire Formats

```
SecretBox:  [16B MAC] [ciphertext]
Stream:     [ciphertext (plaintext + 17B tag embedded)]
Sealed Box: [32B ephemeral_pk] [16B MAC] [ciphertext]
```

### Key Hierarchy

```
User Password
  |
  v (Argon2id)
Key Encryption Key (KEK, 32B)
  |
  +---> (libsodium KDF, context="loginctx", id=1) --> Login Key (16B, for SRP)
  |
  +---> (AES/secretbox wrap) --> Master Key (32B)
                                    |
                                    +---> Collection Key (per collection, 32B)
                                              |
                                              +---> File Key (per file, 32B, random)
                                                        |
                                                        +---> File content (XChaCha20-Poly1305 stream)
                                                        +---> File metadata (XChaCha20-Poly1305)
```

### File Encryption Protocol (Secretstream)

1. Generate random 32-byte `fileKey`
2. `state, header = initPush(fileKey)` -- header is 24 bytes, stored with record
3. For each 4 MiB plaintext slice:
   - Tag = MESSAGE (non-final) or FINAL (last)
   - `cipherChunk = push(state, slice, tag)` -- output = sliceLen + 17
4. Store: header (24B) + concatenated cipher blob
5. Integrity: BLAKE2b hash (64B) over content

Decryption:
1. `state = initPull(header, fileKey)`
2. Read chunks of 4,194,321 bytes; final chunk = remainder
3. `plaintext, tag = pull(state, chunk)` -- nil return = auth failure, abort
4. Expect FINAL tag on last chunk with no trailing bytes

### Collection Architecture (E2EE)

- Master key never leaves client
- Collection key: unique per collection, encrypted to owner's master key
- Shared collections: collection key re-encrypted to each sharee's public key
- File key: re-encrypted with destination collection key per membership
- Server stores only opaque key envelopes; never decrypts

### Security Properties

- Forward secrecy on cast (ephemeral X25519 keypairs)
- Zero-knowledge server architecture
- All operations use AEAD ciphers
- Constant-time operations via libsodium
- Key zeroization via libsodium secure allocators
- Cross-platform test vectors ensure identical crypto output
- Three independent security audits (Cure53, Symbolic Software, Fallible)

---

## 3. Yopass -- Ephemeral Secret Sharing

### Architecture

Client-side encryption with server as blind storage. Server never sees plaintext.

### Encryption

**Client-side (browser/CLI):**
- Algorithm: OpenPGP symmetric encryption
- Cipher: AES-256
- Hash: SHA-256
- Compression: None
- Library: openpgp.js (browser), golang.org/x/crypto/openpgp (CLI)

**Key Generation:**
- 22 bytes from CSPRNG (`crypto/rand`)
- Base64URL encoded, truncated to 22 characters
- Key transmitted via URL fragment (never sent to server)

### Secret Lifecycle

1. Client encrypts message with random key -> PGP armored ciphertext
2. Server validates message is PGP-encrypted (armor decode check)
3. Server stores with UUID v4 key, TTL-based expiration
4. Recipient gets URL: `{base}/#/{type}/{uuid}/{key}`
5. Key in URL fragment -- never sent to server in HTTP request
6. Server supports one-time retrieval (auto-delete after first read)

### Expiration Options

3600s (1 hour), 86400s (1 day), 604800s (1 week)

### Backend Storage

Redis or Memcached -- both ephemeral stores with native TTL support.

### Security Headers (Self-Hosting)

```
Content-Security-Policy:
  default-src 'self';
  font-src 'self' data:;
  form-action 'self';
  frame-ancestors 'none';
  img-src 'self' data:;
  script-src 'self';
  style-src 'self' 'unsafe-inline'

Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000 (HTTPS only)
Cache-Control: private, no-cache (on secret retrieval)
```

### Self-Hosting Security Patterns

- Force one-time secrets mode available (`--force-onetime-secrets`)
- Upload disable option (`--disable-upload`)
- CORS origin configurable (`--cors-allow-origin`)
- Prometheus metrics exposed for monitoring (`/metrics`)
- Health/readiness endpoints for orchestration (`/health`, `/ready`)
- MaxLength limit on encrypted message size
- Trusted proxy configuration for proper IP handling

---

## 4. imgcrypt -- OCI Container Image Encryption

### Architecture

Extends containerd to encrypt/decrypt OCI container image layers using the
`ocicrypt` library. Operates at the container runtime level.

### Encryption Scope

Only **layer content** is encrypted, not manifests or configs. This preserves
image metadata visibility for registries while protecting actual filesystem content.

### Supported Key Providers

Via ocicrypt `CryptoConfig`:
- **PKCS7** -- X.509 certificate-based (RSA/ECDSA)
- **JWE** (JSON Web Encryption) -- public key or symmetric
- **PKCS11** -- Hardware security module (HSM) integration
- **Key provider protocol** -- External key management via gRPC

### Encrypted Media Types

```
application/vnd.oci.image.layer.v1.tar+encrypted          (uncompressed)
application/vnd.oci.image.layer.v1.tar+gzip+encrypted     (gzip compressed)
application/vnd.oci.image.layer.v1.tar+zstd+encrypted     (zstd compressed)
```

### Encryption Flow

1. Read layer data from content store
2. `ocicrypt.EncryptLayer(config, reader, descriptor)` -- wraps symmetric content key
   with recipient public keys, encrypts layer data
3. Encryption metadata stored as OCI descriptor annotations
4. New manifest generated with encrypted layer descriptors
5. Layer finalizer returns annotations containing wrapped keys

### Authorization Model

- `CheckAuthorization()` -- validates key possession without full decryption
- Uses `cryptoOpUnwrapOnly` -- attempts asymmetric unwrap of content key only
- Platform-scoped: only checks layers matching local platform
- Integrates with containerd's `NewContainerOpts` for runtime authorization

### Security Properties

- Per-layer encryption with independent symmetric keys
- Key wrapping enables multi-recipient without re-encryption of data
- Annotations carry encrypted key material (not content)
- Forward-compatible with new compression algorithms (zstd)
- Integration point for HSM-backed key management

---

## 5. Invidious -- Privacy-Preserving YouTube Frontend

### Privacy Protections

- **No Google tracking**: does not use official YouTube APIs, scrapes directly
- **No JavaScript required**: full functionality without client-side JS execution
- **No ads**: strips all YouTube advertising
- **No tracking pixels/beacons**: clean HTML rendering
- **Independent subscriptions**: stored locally, not linked to Google account
- **Proxy capability**: can proxy video streams through the Invidious server
  (`local` preference = true), preventing direct YouTube<->client connection

### Configurable Privacy Features

| Setting | Default | Effect |
|---------|---------|--------|
| `local` | false | Proxy video through Invidious server |
| `thin_mode` | false | Reduce bandwidth/resource usage |
| `https_only` | configurable | Force HTTPS for all resource links |
| `hsts` | true | Strict-Transport-Security header |
| `disable_proxy` | false | Can disable: dash, livestreams, downloads, local |
| `login_enabled` | true | Can disable accounts entirely |
| `registration_enabled` | true | Can disable new registrations |

### Self-Hosting Security

- HMAC key (`hmac_key`) for CSRF token signing and PubSubHubbub verification
- HTTP proxy support for routing YouTube requests through intermediary
- Force IPv4/IPv6 resolution (`force_resolve`) for rate-limit mitigation
- Companion service architecture for load distribution
- AGPL licensed -- modifications must be shared (source code URL configurable)
- Database: PostgreSQL with configurable connection parameters
- Cookie passthrough for authenticated YouTube access (stored in config)
- Socket binding support (Unix domain sockets) for reverse proxy setups

### Limitations

- IP-level tracking still possible at network layer if not proxied
- Rate limiting from YouTube affects instance availability
- Video content itself is still YouTube-hosted (unless fully proxied)
- No E2EE -- privacy is through intermediary, not encryption

---

## 6. HaGeZi DNS Blocklists -- DNS-Level Privacy Protection

### Blocklist Tiers

| Tier | Domains | Blocking Level | Use Case |
|------|---------|---------------|----------|
| Light | 133,434 | Relaxed | No admin available, small list support |
| Normal | 300,829 | Relaxed/Balanced | General use, minimal breakage |
| Pro | 396,118 | Balanced | Recommended default |
| Pro++ | 484,033 | Balanced/Aggressive | Maximum practical protection |
| Ultimate | 545,745 | Aggressive | Full coverage, expect some breakage |

### Specialized Lists

| List | Purpose |
|------|---------|
| Fake | Internet scams, traps, phishing |
| Pop-Up Ads | Malicious pop-up advertising |
| TIF (Threat Intelligence Feeds) | Active threats, IOCs |
| NRD/DGA | Newly registered domains, domain generation algorithms |
| DoH/VPN/TOR/Proxy Bypass | Prevent DNS bypass methods |
| Dynamic DNS | Malicious use of DDNS services |
| Badware Hoster | Abused hosting providers |
| URL Shortener | Link shortener abuse |
| Most Abused TLDs | Known-malicious top-level domains |
| DNS Rebind Protection | Prevents resolving to local/private IPs |
| Native Tracker | Device/OS-level telemetry (per vendor) |
| NSFW / Gambling / Piracy / Social | Content category blocking |

### Supported Formats

Domains, Hosts, Adblock, DNSMasq, Wildcard, RPZ (Response Policy Zone),
PAC (Proxy Auto Configuration), AdGuard, ControlD.

### Compatible DNS Software

Pi-hole, AdGuard Home, NextDNS, Blocky, DNSCrypt, TechnitiumDNS,
pfBlockerNG, Unbound, Bind, Knot, PowerDNS, OPNsense, OpenSnitch,
Little Snitch Mini, uBlock Origin (browser-level).

### Security Architecture Pattern

DNS sinkholing: queries for known-bad domains return NXDOMAIN or 0.0.0.0,
preventing the connection from being established. Applied at network edge
(router/DNS resolver) for whole-network protection without per-device agents.

---

## 7. Betterfox -- Firefox Privacy Hardening

### Tracking Protection Configuration

```javascript
// ETP Strict Mode (Total Cookie Protection)
user_pref("browser.contentblocking.category", "strict");

// Global Privacy Control signal
user_pref("privacy.globalprivacycontrol.enabled", true);

// Isolate content script resources
user_pref("privacy.antitracking.isolateContentScriptResources", true);

// Disable CSP Level 2 reporting (prevents beacon to third parties)
user_pref("security.csp.reporting.enabled", false);
```

### TLS/SSL Hardening

```javascript
// Disable 0-RTT (not forward secret, replay vulnerable)
user_pref("security.tls.enable_0rtt_data", false);

// Display warning for unsafe TLS negotiation
user_pref("security.ssl.treat_unsafe_negotiation_as_broken", true);

// Post-quantum key exchange (Kyber/ML-KEM)
// user_pref("security.tls.enable_kyber", true);
// user_pref("network.http.http3.enable_kyber", true);
```

### Certificate Handling

```javascript
// Disable OCSP (leaks visited domains to CA)
user_pref("security.OCSP.enabled", 0);

// CRLite preferred over OCSP (faster, more private)
// user_pref("security.pki.crlite_mode", 2);  // DEFAULT FF142+

// HPKP strict mode (prevent MITM even with valid CA cert)
// user_pref("security.cert_pinning.enforcement_level", 2);

// Distrust OS-installed root certificates
// user_pref("security.enterprise_roots.enabled", false);
```

### Speculative Connection Prevention

```javascript
// Kill all speculative pre-connections
user_pref("network.http.speculative-parallel-limit", 0);

// Disable DNS prefetching
user_pref("network.dns.disablePrefetch", true);
user_pref("network.dns.disablePrefetchFromHTTPS", true);

// Disable link prefetching
user_pref("network.prefetch-next", false);

// Disable URL bar speculative connections
user_pref("browser.urlbar.speculativeConnect.enabled", false);
user_pref("browser.places.speculativeConnect.enabled", false);
```

### Disk Avoidance (Anti-Forensics)

```javascript
// Disable disk cache (memory only)
user_pref("browser.cache.disk.enable", false);

// Force media cache to memory in Private Browsing
user_pref("browser.privatebrowsing.forceMediaMemoryCache", true);
user_pref("media.memory_cache_max_size", 65536); // 64 MB

// Reduce session save frequency
user_pref("browser.sessionstore.interval", 60000); // 1 min vs 15s default
```

### Search Privacy

```javascript
// Disable search suggestions (keylogging to search engine)
user_pref("browser.search.suggest.enabled", false);

// Disable Firefox Suggest
user_pref("browser.urlbar.quicksuggest.enabled", false);

// Disable form autofill (third-party readable)
user_pref("browser.formfill.enable", false);

// Show Punycode for IDN (anti-homograph attack)
user_pref("network.IDN_show_punycode", true);

// Separate search engine for Private Browsing
user_pref("browser.search.separatePrivateDefault.ui.enabled", true);
```

### State Partitioning (dFPI / Total Cookie Protection)

Partitions by top-level eTLD+1:
- HTTP cache, image cache, favicon cache
- HSTS cache, OCSP cache, style sheet cache
- Font cache, DNS cache, HTTP Auth cache
- Alt-Svc cache, TLS certificate cache
- Cookies, localStorage, IndexedDB, service workers

### Key Hardening Preferences Summary

| Category | Pref | Value | Impact |
|----------|------|-------|--------|
| ETP Mode | browser.contentblocking.category | strict | TCP + fingerprint protection |
| GPC Signal | privacy.globalprivacycontrol.enabled | true | Legal privacy signal |
| OCSP | security.OCSP.enabled | 0 | Prevents CA domain leaks |
| 0-RTT | security.tls.enable_0rtt_data | false | Prevents replay attacks |
| Disk Cache | browser.cache.disk.enable | false | No persistent cache |
| DNS Prefetch | network.dns.disablePrefetch | true | No speculative DNS |
| Link Prefetch | network.prefetch-next | false | No speculative page loads |
| Speculative Conn | network.http.speculative-parallel-limit | 0 | No pre-connections |
| Form History | browser.formfill.enable | false | No autocomplete data |
| Punycode | network.IDN_show_punycode | true | IDN homograph defense |
| UITour | browser.uitour.enabled | false | No remote page control |

---

## 8. External Reference Summaries

### EFF Surveillance Self-Defense (ssd.eff.org)

Core threat modeling questions:
1. What do I want to protect? (assets)
2. Who do I want to protect it from? (adversaries)
3. How likely is it I will need to protect it? (risk)
4. How bad are the consequences if I fail? (impact)
5. How much trouble am I willing to go through? (cost)

Tool recommendations: Signal, Tor, password managers, full-disk encryption.
Scenario-based guidance for journalists, activists, human rights defenders.

### PrivacyTools.io

Recommended tool categories:
- VPN: Surfshark, NordVPN (audited providers)
- Email: StartMail (encrypted, unlimited aliases), ProtonMail
- Browser: LibreWolf, Brave, Firefox Focus
- Search: Brave Search (independent index), MetaGer
- Messaging: Session (decentralized, Lokinet-routed, no phone/email required)
- Cloud: Internxt (audited by Securitum), Proton Drive
- DNS: NextDNS (300K free queries/month)
- OS: Whonix (all traffic through Tor)
- Disk cleaner: BleachBit (file shredding)

### PRISM Break (prism-break.org)

Goal: make mass surveillance uneconomical. Provides per-platform (Android, iOS,
BSD, GNU/Linux, macOS, Windows, routers, servers) recommendations for replacing
proprietary services with open-source, encryption-capable alternatives.

---

## 9. Cross-Cutting Security Patterns

### Key Derivation Best Practices (Observed)

| System | Algorithm | Memory | Time | Salt | Output |
|--------|-----------|--------|------|------|--------|
| Cryptomator | scrypt | N=32768, r=8 | -- | Random | 32B KEK |
| Ente | Argon2id (interactive) | 64 MB | 2 ops | 16B random | 32B KEK |
| Ente | Argon2id (sensitive) | 1 GB | 4 ops | 16B random | 32B KEK |
| Yopass | None (random key) | -- | -- | -- | 22B random |

### Encryption Architecture Patterns

**Pattern: Per-file random key with key hierarchy**
Used by Cryptomator and Ente. Each file gets a random symmetric key. That key
is encrypted with a collection/vault key, which is itself encrypted with the
master key. Compromise of one file key does not reveal others.

**Pattern: Client-side encryption with blind server**
Used by Yopass, Ente, Cryptomator. Server never possesses plaintext or key material.
Server stores opaque encrypted blobs and wrapped key envelopes.

**Pattern: Key-in-fragment URL sharing**
Used by Yopass. Encryption key placed in URL fragment (`#`), which is never sent
to the server in HTTP requests. Only the client-side JavaScript/receiver sees it.

**Pattern: Chunked authenticated encryption**
Used by both Cryptomator (32 KiB AES-GCM chunks) and Ente (4 MiB XChaCha20-Poly1305
secretstream). Chunk numbering or stream state prevents reordering/truncation.
Per-chunk authentication allows streaming decryption with early tamper detection.

**Pattern: Layer-level container encryption**
Used by imgcrypt/ocicrypt. Only data layers encrypted, metadata remains visible
for registry operations. Symmetric content key wrapped per-recipient with
asymmetric cryptography, enabling multi-party access without re-encryption.

### Self-Hosting Security Checklist (Derived)

1. **TLS everywhere** -- HSTS headers, HTTPS-first/only mode
2. **Strict CSP** -- `default-src 'self'`, `frame-ancestors 'none'`
3. **No referrer leakage** -- `Referrer-Policy: no-referrer`
4. **CSRF protection** -- HMAC-signed tokens, SameSite cookies
5. **Rate limiting** -- per-IP, per-endpoint
6. **Ephemeral storage** -- TTL-based expiration for secrets (Redis/Memcached)
7. **Health/readiness probes** -- separate liveness (process alive) from readiness (can serve)
8. **Metrics** -- Prometheus counters for requests by method/path/status
9. **Input validation** -- verify encryption format before storage (Yopass: PGP armor check)
10. **Trusted proxy config** -- proper X-Forwarded-For handling
11. **Disk avoidance** -- in-memory caches, no persistent logs of sensitive data
12. **DNS-level blocking** -- deploy HaGeZi Pro+ or equivalent at network edge
13. **Browser hardening** -- deploy Betterfox/arkenfox user.js for client endpoints

### Privacy Engineering Principles (Synthesized)

1. **Zero-knowledge by design** -- server architecture must function without
   access to plaintext. Key hierarchy ensures only clients hold decryption keys.
2. **Minimize metadata** -- encrypt filenames (Cryptomator), use sealed boxes
   for anonymous transmission (Ente), strip referrers and tracking parameters.
3. **Defense in depth** -- DNS blocking (network) + browser hardening (client) +
   E2EE (application) + TLS (transport) for layered protection.
4. **Authenticate before decrypt** -- AEAD ciphers (AES-GCM, XChaCha20-Poly1305)
   verify integrity before exposing plaintext, preventing oracle attacks.
5. **Ephemeral by default** -- secrets should auto-expire (Yopass TTLs),
   session keys should not persist (Ente: no persistent key storage on tvOS),
   browser caches should be memory-only.
6. **Key zeroization** -- explicit memory clearing after key use
   (Cryptomator: `Arrays.fill(rawKey, (byte) 0x00)`, Ente: libsodium secure allocators).
7. **Partition state** -- Total Cookie Protection (dFPI) partitions all browser
   state by top-level origin, preventing cross-site tracking through cache,
   cookies, or network state.
