Privacy, Cryptography & Self-Hosting Security -- Deep Training Notes
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 +
.c9rextension - Long names (>220 chars encoded): SHA-1 hash +
.c9sextension (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)
- Generate random 32-byte
fileKey state, header = initPush(fileKey)-- header is 24 bytes, stored with record- For each 4 MiB plaintext slice:
- Tag = MESSAGE (non-final) or FINAL (last)
cipherChunk = push(state, slice, tag)-- output = sliceLen + 17
- Store: header (24B) + concatenated cipher blob
- Integrity: BLAKE2b hash (64B) over content
Decryption:
state = initPull(header, fileKey)- Read chunks of 4,194,321 bytes; final chunk = remainder
plaintext, tag = pull(state, chunk)-- nil return = auth failure, abort- 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
- Client encrypts message with random key -> PGP armored ciphertext
- Server validates message is PGP-encrypted (armor decode check)
- Server stores with UUID v4 key, TTL-based expiration
- Recipient gets URL:
{base}/#/{type}/{uuid}/{key} - Key in URL fragment -- never sent to server in HTTP request
- 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
- Read layer data from content store
ocicrypt.EncryptLayer(config, reader, descriptor)-- wraps symmetric content key with recipient public keys, encrypts layer data- Encryption metadata stored as OCI descriptor annotations
- New manifest generated with encrypted layer descriptors
- 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
NewContainerOptsfor 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
(
localpreference = 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
// 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
// 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
// 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
// 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)
// 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
// 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:
- What do I want to protect? (assets)
- Who do I want to protect it from? (adversaries)
- How likely is it I will need to protect it? (risk)
- How bad are the consequences if I fail? (impact)
- 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)
- TLS everywhere -- HSTS headers, HTTPS-first/only mode
- Strict CSP --
default-src 'self',frame-ancestors 'none' - No referrer leakage --
Referrer-Policy: no-referrer - CSRF protection -- HMAC-signed tokens, SameSite cookies
- Rate limiting -- per-IP, per-endpoint
- Ephemeral storage -- TTL-based expiration for secrets (Redis/Memcached)
- Health/readiness probes -- separate liveness (process alive) from readiness (can serve)
- Metrics -- Prometheus counters for requests by method/path/status
- Input validation -- verify encryption format before storage (Yopass: PGP armor check)
- Trusted proxy config -- proper X-Forwarded-For handling
- Disk avoidance -- in-memory caches, no persistent logs of sensitive data
- DNS-level blocking -- deploy HaGeZi Pro+ or equivalent at network edge
- Browser hardening -- deploy Betterfox/arkenfox user.js for client endpoints
Privacy Engineering Principles (Synthesized)
- Zero-knowledge by design -- server architecture must function without access to plaintext. Key hierarchy ensures only clients hold decryption keys.
- Minimize metadata -- encrypt filenames (Cryptomator), use sealed boxes for anonymous transmission (Ente), strip referrers and tracking parameters.
- Defense in depth -- DNS blocking (network) + browser hardening (client) + E2EE (application) + TLS (transport) for layered protection.
- Authenticate before decrypt -- AEAD ciphers (AES-GCM, XChaCha20-Poly1305) verify integrity before exposing plaintext, preventing oracle attacks.
- 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.
- Key zeroization -- explicit memory clearing after key use
(Cryptomator:
Arrays.fill(rawKey, (byte) 0x00), Ente: libsodium secure allocators). - Partition state -- Total Cookie Protection (dFPI) partitions all browser state by top-level origin, preventing cross-site tracking through cache, cookies, or network state.