Encryption Architecture Guide
Technical guide to PVTLNK's encryption and cryptographic architecture
Related Document: Privacy & Security Whitepaper
Complete explanation of our privacy protections and zero-knowledge architecture
π PVTLNK Encryption Architecture Guide
Understanding Our Security Architecture
Version 2.0 | Last Updated: November 2nd, 2025
Executive Summary
This document explains the encryption and cryptographic architecture used in PVTLNK, why we chose each method, and why our approach provides superior security and privacy compared to traditional systems.
Our Philosophy: Use the right cryptographic tool for each job, implement it correctly, and never store anything that can be reverse-engineered.
Relationship to Privacy Whitepaper: This document focuses on the technical βhowβ of our encryption architecture. The Privacy & Security Whitepaper focuses on the βwhatβ we protect and βwhyβ it matters. Together, they provide a complete picture of PVTLNKβs security.
1. Types of Encryption & Cryptographic Functions
Understanding the Different Tools
Cryptography uses different tools for different purposes. Understanding these helps explain why our architecture is superior.
Hash Functions (One-Way Functions)
What They Are: - Mathematical functions that take input and produce fixed-size output - One-way: Easy to compute hash from input, impossible to compute input from hash - Deterministic: Same input always produces same output - Avalanche Effect: Tiny input change = completely different output
Common Uses: - Password hashing (with salt) - Data integrity verification - Digital signatures - Commitment schemes (like we use)
Examples: SHA-256, MD5 (deprecated), SHA-3
What We Use: SHA-256 for all security-critical hashing
Key Derivation Functions (KDFs)
What They Are: - Functions that derive cryptographic keys from passwords - Key Stretching: Make computation slow to prevent brute force - Use many iterations (typically 100,000+) - Designed specifically for password-derived keys
Common Uses: - Deriving encryption keys from passwords - Password hashing (slower than simple hashing) - Key generation
Examples: PBKDF2, Argon2, bcrypt, scrypt
What We Use: PBKDF2 (100,000 iterations) for commitment generation
Symmetric Encryption
What It Is: - Same key used to encrypt and decrypt - Fast and efficient - Used for bulk data encryption
Common Uses: - Database encryption - TLS/SSL (part of it) - File encryption
What We Use: AES-256 (via Exoscale) for database encryption at rest
Asymmetric Encryption (Public-Key)
What It Is: - Different keys for encryption and decryption - Public key encrypts, private key decrypts - Slower than symmetric encryption
Common Uses: - TLS/SSL certificates - Digital signatures - Key exchange
What We Use: TLS 1.3 (which uses asymmetric + symmetric) for traffic encryption
Password Hashing (Specialized)
What It Is: - Specialized form of key derivation for passwords - Slow by design (prevents brute force) - Automatically includes salt
Examples: BCrypt, Argon2, PBKDF2
What We Use: BCrypt for link password protection, PBKDF2 for commitments
2. Our Encryption Architecture
The Multi-Layer Approach
We use different cryptographic methods for different purposes, each chosen for its specific strengths.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLIENT-SIDE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Username β SHA-256 β Nonce (deterministic) β
β Password + Nonce β PBKDF2 (100k) β Commitment β
β (Username & Password NEVER leave browser) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
[Only Commitment + Nonce Sent]
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SERVER-SIDE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Commitment β Stored (64-char hex hash) β
β Nonce β Stored (64-char hex hash) β
β IP β Geolocate β Hash with SHA-256 + Salt β Store β
β Link Password β BCrypt β Store β
β URLs β Stored in plain text (database encrypted) β
β Database β AES-256 (Exoscale instance disk) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
[TLS 1.3 Encryption in Transit]
β
[Your Browser]
Important Clarification: - URLs are stored in plain text within the database (necessary for link redirection) - The database itself is encrypted at rest (AES-256) by Exoscaleβs instance disk encryption - This means: URLs are accessible to the application (required for functionality), but the entire database storage is encrypted by infrastructure - Usernames and passwords are never stored - only cryptographic commitments and nonces
3. Why We Use Each Method
SHA-256 for Core Hashing
Where We Use It: - Username hashing (client-side only) β Nonce generation - IP address anonymization (with server-specific salt) - Visitor fingerprinting - QR code uniqueness - A/B test variant assignment - Commitment hash generation (used as input to PBKDF2)
Why SHA-256?: 1. Cryptographically Secure: NIST-approved, used by Bitcoin, TLS 2. One-Way Function: Mathematically impossible to reverse 3. Collision Resistant: No practical way to find two inputs with same hash 4. Fast: Efficient computation (but see PBKDF2 for key stretching) 5. Standard: Industry standard, well-tested, widely supported
Why Not MD5 or SHA-1?: - β MD5: Cryptographically broken (collisions found in seconds) - β SHA-1: Vulnerable to collision attacks (deprecated by NIST) - β SHA-256: No known vulnerabilities, secure for decades
Example: ```ruby # IP Anonymization (Server-Side) # Step 1: Get real IP temporarily (in-memory only) ip_address = request.remote_ip # e.g., β203.0.113.42β
Step 2: Geolocate using real IP
geo_data = GeolocationService.geolocate_ip(ip_address)
Step 3: Hash IP with server-specific salt
salt = Rails.application.secret_key_base hashed_ip = Digest::SHA256.hexdigest(β#{ip_address}_#{salt}β) # Original IP: β203.0.113.42β # Hash: βa3f5b9c2d1e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2β # Original IP discarded immediately after hashing # Hash stored, cannot be reversed (one-way function)
Step 4: Store only hash + country-level geolocation
ClickAnalytic.create( hashed_ip: hashed_ip, country: geo_data[:country], # Country-level only (e.g., βUSβ) city: geo_data[:city] # City set to nil if unknown/invalid ) ```
Username Hashing (Client-Side):
javascript
// Username β Nonce (Client-Side Only)
const username = "myusername"; // Never transmitted
const usernameBytes = new TextEncoder().encode(username);
const usernameHash = await crypto.subtle.digest('SHA-256', usernameBytes);
const nonceHex = Array.from(new Uint8Array(usernameHash))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
// Result: 64-character hex string
// Username discarded, nonce cannot reveal username (one-way function)
PBKDF2 for Commitment Generation
Where We Use It: - Client-side commitment creation (signup, login, password reset) - Wraps SHA-256 with key stretching
Why PBKDF2?:
1. Key Stretching: 100,000 iterations slow brute force by 100,000x
2. Password-Derived Keys: Designed specifically for deriving keys from passwords
3. Industry Standard: NIST-recommended for password-based key derivation
4. Client-Side Compatible: Works in browser crypto.subtle API
5. Salting Built-In: Uses nonce as salt (deterministic but secure)
Why PBKDF2 Instead of Just SHA-256?: - SHA-256 Alone: Fast (vulnerable to brute force) - PBKDF2 with SHA-256: Slow (100k iterations = 100,000x slower) - Result: Even with commitment hash, brute force takes 100,000x longer
Example: ```javascript // Client-side commitment generation (Complete Flow) // Step 1: Generate nonce from username (already done) const nonceHex = ββ¦β; // From username hash
// Step 2: Create commitment from password + nonce const password = βMySecurePassword123β; const passwordBytes = new TextEncoder().encode(password); const keyMaterial = await crypto.subtle.importKey( βrawβ, passwordBytes, βPBKDF2β, false, [βderiveBitsβ] );
const commitmentBits = await crypto.subtle.deriveBits({ name: βPBKDF2β, salt: new TextEncoder().encode(nonceHex), // Nonce from username iterations: 100000, // 100k iterations = key stretching hash: βSHA-256β }, keyMaterial, 256);
const commitmentHex = Array.from(new Uint8Array(commitmentBits)) .map(b => b.toString(16).padStart(2, β0β)) .join(ββ); // Result: 64-character hex string // Takes ~10-50ms (slow enough to prevent brute force) // Password and username discarded, never transmitted ```
Security Property: - Even if attacker gets commitment hash, brute force requires 100,000x more computation - With 2^256 possible outputs, brute force is computationally infeasible
BCrypt for Link Passwords
Where We Use It: - Link password protection (optional feature) - Passwords users set for individual links
Why BCrypt?: 1. Adaptive Hashing: Cost factor can increase over time 2. Automatic Salting: Salt included in hash (unique per password) 3. Slow by Design: Intentionally slow to prevent brute force 4. Industry Standard: Most common password hashing algorithm 5. Rails Integration: Built into Rails, well-tested
Why BCrypt for Link Passwords?: - Link passwords are traditional passwords (user chooses them) - BCrypt is designed specifically for this use case - Provides adaptive security (can increase cost factor)
Example:
ruby
# Link password hashing
password_hash = BCrypt::Password.create(password)
# Format: "$2a$10$..." (includes salt, cost factor)
# Cannot be reversed
AES-256 for Database Encryption
Where We Use It: - Database encryption at rest (via Exoscale) - Storage volume encryption
Why AES-256?: 1. Industry Standard: Used by governments, banks, military 2. Symmetric Encryption: Fast and efficient for bulk data 3. 256-bit Keys: 2^256 possible keys (computationally infeasible) 4. Hardware Accelerated: Modern CPUs have AES acceleration 5. Well-Tested: Decades of use, no practical vulnerabilities
Why AES-256 for Database?: - Databases store large amounts of data (needs fast encryption) - Symmetric encryption is efficient for bulk storage - 256-bit provides maximum security
How It Works: - Exoscale provides AES-256 encryption for instance disks (automatic) - All database files stored on encrypted instance disk - Docker volumes inherit instance disk encryption - Transparent to application (handled by infrastructure) - No additional configuration required - always encrypted
Important Clarification: - Database encryption at rest: Entire database storage volume encrypted (AES-256) - URL storage: URLs stored in plain text within the database (required for functionality) - Why URLs in plain text: Link redirection requires the application to read destination URLs - Privacy protection: Even though URLs are in plain text, zero-knowledge authentication ensures your username/password are never stored, and IP addresses are hashed
What This Means: - Database files are encrypted (physical security) - If someone steals database files, theyβre encrypted - Application can access URLs (by design, for link functionality) - Personal identifiers (username, password, IP) are never stored or are hashed
TLS 1.3 for Traffic Encryption
Where We Use It: - All network traffic (HTTPS) - Between browser and server - Between server and external APIs
Why TLS 1.3?: 1. Latest Standard: Most secure TLS version 2. Perfect Forward Secrecy: Each connection uses unique keys 3. Asymmetric + Symmetric: Best of both worlds 4. Certificate Verification: Prevents man-in-the-middle attacks 5. Industry Standard: Used by all major websites
How It Works: 1. Handshake: Uses asymmetric encryption (RSA/ECDSA) to exchange keys 2. Data Transfer: Uses symmetric encryption (AES) for speed 3. Certificate Chain: Verifies server identity
What We Configure: - Force HTTPS in production - HSTS headers (Strict-Transport-Security) - Letβs Encrypt certificates (automatic renewal)
4. Why Our Architecture Is Superior
Traditional Systems vs. PVTLNK
Traditional System (Standard Authentication)
User enters: Email + Password
β
Server receives: Email (plaintext) + Password (plaintext in transit)
β
Server stores: Email (plaintext) + Password Hash (BCrypt)
β
Problem: Email is stored and can identify you
Vulnerabilities: - β Email stored (can identify you) - β Password transmitted to server (even if encrypted in TLS) - β Database breach = email addresses exposed - β Can link activity to identity
PVTLNK System (Zero-Knowledge Architecture)
User enters: Username + Password
β
Browser hashes: Username β SHA-256 β Nonce (deterministic)
Browser hashes: Password + Nonce β PBKDF2 (100k) β Commitment
β
Server receives: Commitment (hash) + Nonce (hash)
β
Server stores: Commitment (hash) + Nonce (hash)
β
Result: Username & Password NEVER transmitted or stored
Key Difference: We use username (not email), and username never leaves your browser.
Advantages: - β Username never transmitted (only nonce derived from it, client-side only) - β Password never transmitted (only commitment derived from it) - β Database breach = only hashes (cannot be reversed) - β Cannot link activity to identity (no personal identifiers) - β Email addresses never collected or stored - β Even developers cannot access usernames/passwords (never stored)
Why Each Layer Matters
Layer 1: Client-Side Hashing (SHA-256 β PBKDF2)
What It Does: - Username hashed to nonce (deterministic, client-side only, never leaves browser) - Password stretched with PBKDF2 (never leaves browser) - Only commitment and nonce hashes transmitted (both are irreversible)
Why Itβs Better: - Traditional: Password sent to server (even if encrypted in TLS) - PVTLNK: Password and username never leave browser - Result: Even if TLS is broken, password and username are never exposed - Additional Security: Username doesnβt even exist server-side (never transmitted)
Layer 2: Key Stretching (PBKDF2)
What It Does: - 100,000 iterations slow brute force attacks - Makes commitments computationally expensive to crack
Why Itβs Better: - Traditional: Fast hashing (vulnerable to brute force) - PVTLNK: Slow hashing (100,000x slower) - Result: Even with commitment hash, brute force is infeasible
Layer 3: Salting
What It Does: - IP hashing uses server secret as salt - Prevents rainbow table attacks - Makes each hash unique to our server
Why Itβs Better: - Without Salt: Same IP always produces same hash (vulnerable) - With Salt: Server-specific hashing (cannot compare across servers) - Result: Even with hash, cannot reverse IP or create rainbow tables
Layer 4: TLS Encryption
What It Does: - Encrypts all traffic in transit - Prevents interception
Why Itβs Better: - Additional Layer: Even if commitment intercepted, itβs encrypted - Defense in Depth: Multiple layers of protection - Result: Intercepted traffic is useless (encrypted + irreversible)
Layer 5: Database Encryption
What It Does: - Encrypts database at rest (AES-256) - Protects against physical access
Why Itβs Better: - Physical Security: Even with database files, data is encrypted - Infrastructure Security: Handled by Exoscale - Result: Database files useless without decryption key
5. Why We Donβt Use Other Methods
Why Not Argon2 Instead of PBKDF2?
Argon2: - β More modern (winner of Password Hashing Competition) - β Memory-hard (more resistant to ASIC attacks) - β Less browser support (requires polyfill) - β More complex to implement - β PBKDF2 sufficient for our use case
Our Choice: PBKDF2
- β
Native browser support (crypto.subtle)
- β
Simpler implementation
- β
Sufficient security (100k iterations)
- β
Industry standard
Note: PBKDF2 is NIST-recommended and secure. Argon2 would be slightly stronger, but PBKDF2 provides adequate security for our needs.
Why Not RSA or ECC for Commitments?
RSA/ECC (Asymmetric Encryption): - β Can encrypt and decrypt - β Slower than hashing - β Requires key management - β Not needed for commitments (we donβt need to decrypt)
Our Choice: Hash Functions (SHA-256 + PBKDF2) - β One-way (we never need to decrypt) - β Faster computation - β No key management - β Perfect for commitment schemes
Why: Commitments are hashes, not encrypted data. We never need to decrypt them - we only need to verify they match.
Why Not ChaCha20-Poly1305?
ChaCha20-Poly1305: - β Modern stream cipher - β Fast on devices without AES hardware - β οΈ Used in TLS 1.3 (but we use AES via TLS)
Our Choice: AES-256 (via TLS/Exoscale) - β Industry standard - β Hardware accelerated - β Proven over decades - β Used by our infrastructure provider
Note: TLS 1.3 supports both AES and ChaCha20. We use whatever TLS negotiates (typically AES with hardware acceleration).
6. Our Unique Architecture Advantages
Advantage 1: Zero-Knowledge by Design
Traditional: Server knows your email
PVTLNK: Server never receives your email
How: Client-side hashing means email never leaves browser.
Result: Even if server is compromised, your email is never exposed.
Advantage 2: Defense in Depth
Multiple Layers: 1. Client-side hashing (password never transmitted) 2. PBKDF2 key stretching (slow brute force) 3. SHA-256 hashing (cannot reverse) 4. Salting (prevents rainbow tables) 5. TLS encryption (protects in transit) 6. Database encryption (protects at rest)
Traditional: Usually 2-3 layers
PVTLNK: 6 layers of protection
Result: Even if one layer fails, others provide protection.
Advantage 3: No Single Point of Failure
If TLS is Broken: - β Commitment hash is still irreversible - β Password never transmitted anyway - β Multiple layers still protect
If Database is Breached: - β Only hashes stored (cannot reverse) - β No emails to identify users - β IPs hashed with salt (cannot reverse)
If Client is Compromised: - β Password still requires brute force (PBKDF2) - β Server validates commitments (cannot fake) - β Session rotation prevents replay
Advantage 4: Privacy-First Design
Traditional: Privacy added as afterthought
PVTLNK: Privacy designed from ground up
How: - Zero-knowledge architecture (not just encryption) - Client-side processing (data never leaves browser) - Anonymous by default (no personal identifiers) - Swiss hosting (legal privacy protections)
Result: Privacy is a fundamental feature, not an add-on.
7. Cryptographic Security Standards
NIST Compliance
Our Implementation: - β SHA-256 (NIST approved) - β PBKDF2 (NIST SP 800-132 recommended) - β AES-256 (NIST approved) - β BCrypt (industry standard) - β TLS 1.3 (latest standard) - β No MD5 (deprecated) - β No SHA-1 (deprecated)
Rating: β Fully NIST Compliant
OWASP Recommendations
Our Implementation: - β Strong cryptographic algorithms (SHA-256, PBKDF2, AES-256) - β No weak algorithms (MD5, SHA-1 eliminated) - β Salted hashing (IP hashing uses salt) - β Secure key management (encrypted credentials) - β TLS/SSL enforcement (Force SSL enabled)
Rating: β Exceeds OWASP Recommendations
Industry Best Practices
Our Implementation: - β Client-side password hashing (rare, superior) - β Key stretching (PBKDF2 100k iterations) - β Session rotation (prevents fixation) - β Timing attack protection (random delays) - β Perfect Forward Secrecy (TLS 1.3) - β Database encryption at rest (AES-256)
Rating: β Exceeds Industry Best Practices
8. Why This Structure Is Best
Comparison Matrix
| Feature | Traditional Systems | PVTLNK | Advantage |
|---|---|---|---|
| Email Storage | β Stored (plaintext) | β Never stored | PVTLNK: Privacy |
| Password Transmission | β Sent to server | β Never transmitted | PVTLNK: Security |
| Password Storage | β BCrypt hash | β Commitment (PBKDF2) | PVTLNK: Stronger |
| Key Stretching | β Rare | β PBKDF2 (100k) | PVTLNK: Protection |
| IP Anonymization | β Rare | β SHA-256 + Salt | PVTLNK: Privacy |
| Session Rotation | β οΈ Sometimes | β Always | PVTLNK: Security |
| Timing Protection | β Rare | β Random delays | PVTLNK: Security |
| Tor Support | β None | β Detection + Logging | PVTLNK: Privacy |
| Zero-Knowledge | β No | β Yes | PVTLNK: Privacy |
Why Our Approach Wins
1. Privacy by Design, Not by Promise
Traditional: βWe promise not to look at your dataβ
PVTLNK: βWe physically cannot look at your dataβ
Difference: Mathematical impossibility vs. policy promise
2. Multiple Layers of Security
Traditional: 2-3 security layers
PVTLNK: 6+ security layers
Example Attack Scenarios: - TLS Broken: Still have irreversible commitments - Database Breached: Still have hashed data - Server Compromised: Still cannot identify users
3. Client-Side Processing
Traditional: Trust server with password
PVTLNK: Never send password to server
Result: Even malicious server cannot access password
4. Swiss Legal Protections
Traditional: Subject to local jurisdiction
PVTLNK: Swiss privacy laws (strongest globally)
Result: Additional legal layer of protection
9. Real-World Attack Scenarios
Scenario 1: Database Breach
Traditional System:
Attacker gets: Emails, Password hashes, IP addresses
Result: Can identify users, attempt password cracking, link activity
PVTLNK:
Attacker gets: Commitment hashes, Nonce hashes, Hashed IPs
Result: Cannot identify users, cannot reverse hashes, cannot link activity
Why We Win: Hashes cannot be reversed (mathematical impossibility)
Scenario 2: Man-in-the-Middle (MITM)
Traditional System:
Attacker intercepts: Email (in TLS), Password (in TLS)
If TLS broken: Email and password exposed
PVTLNK:
Attacker intercepts: Commitment hash (in TLS), Nonce hash (in TLS)
If TLS broken: Only hashes exposed (cannot be reversed)
Why We Win: Even with TLS broken, password never transmitted
Scenario 3: Server Compromise
Traditional System:
Attacker controls server: Can read database, view emails, access passwords
Result: Complete breach of user data
PVTLNK:
Attacker controls server: Can read database (only hashes), cannot view emails, cannot access passwords
Result: Database useless (only hashes)
Why We Win: Zero-knowledge means server cannot access data
Scenario 4: Insider Threat
Traditional System:
Developer access: Can read emails, view user activity, identify users
Result: Privacy violation possible
PVTLNK:
Developer access: Can read hashes, cannot view emails, cannot identify users
Result: Privacy maintained (cannot identify users)
Why We Win: Even developers cannot access user data
10. Technical Deep Dive
Commitment Generation (Step-by-Step)
```javascript // Step 1: Username β Nonce (Client-Side Only) const username = βmyusernameβ; // Never transmitted to server const usernameBytes = new TextEncoder().encode(username); const usernameHash = await crypto.subtle.digest(βSHA-256β, usernameBytes); const nonceHex = Array.from(new Uint8Array(usernameHash)) .map(b => b.toString(16).padStart(2, β0β)) .join(ββ); // Result: βa3f5b9c2d1e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2β // Username discarded immediately, nonce never reveals username // Nonce is deterministic: same username always produces same nonce
// Step 2: Password + Nonce β Commitment (Client-Side) const password = βMySecurePassword123β; const keyMaterial = await crypto.subtle.importKey(βrawβ, password, βPBKDF2β, false, [βderiveBitsβ]); const commitmentBits = await crypto.subtle.deriveBits({ name: βPBKDF2β, salt: nonceHex, // Salt from email hash iterations: 100000, // Key stretching hash: βSHA-256β }, keyMaterial, 256); const commitment = Array.from(new Uint8Array(commitmentBits)) .map(b => b.toString(16).padStart(2, β0β)) .join(ββ); // Result: βb7d2e8f1a3c5d9e7f2a4b6c8d0e3f5a7b9c1d3e5f7a9b1c3d5e7f9a1b3c5d7e9β // Password discarded, commitment never reveals password
// Step 3: Send to Server // Only commitment and nonce sent (both are hashes) // Username and password never transmitted ```
Security Properties: - β Username never leaves browser (only nonce derived from it) - β Password never leaves browser (only commitment derived from it) - β Nonce cannot reveal username (SHA-256 is one-way) - β Commitment cannot reveal password (PBKDF2 is one-way) - β 100,000 iterations = 100,000x slower brute force - β Deterministic nonce ensures consistent authentication (same username β same nonce)
IP Anonymization (Step-by-Step)
```ruby # Step 1: Get Real IP (Temporary, In-Memory) ip_address = request.remote_ip # e.g., β203.0.113.42β
Step 2: Geolocate (Using Real IP)
geo_data = GeolocationService.geolocate_ip(ip_address) # Result: { country: βUSβ, city: βNew Yorkβ }
Step 3: Hash IP with Salt
salt = Rails.application.secret_key_base # Server-specific secret hashed_ip = Digest::SHA256.hexdigest(β#{ip_address}_#{salt}β) # Result: βb7d2e8f1a3c5d9e7f2a4b6c8d0e3f5a7b9c1d3e5f7a9b1c3d5e7f9a1b3c5d7e9β
Step 4: Store Hash + Geolocation
ClickAnalytic.create( hashed_ip: hashed_ip, # Stored country: geo_data[:country], # Stored (country-level only) # Original IP discarded (never stored) ) ```
Security Properties: - β Real IP used only temporarily for geolocation - β IP immediately hashed before storage - β Salt prevents rainbow table attacks - β Server-specific salt (cannot compare across servers) - β Hash cannot be reversed (SHA-256 is one-way)
11. Why Our Structure Is Best: Summary
Mathematical Security
Traditional: βWe wonβt look at your dataβ (policy)
PVTLNK: βWe cannot look at your dataβ (mathematics)
Difference: Promise vs. impossibility
Defense in Depth
Traditional: 2-3 security layers
PVTLNK: 6+ security layers
Each Layer: 1. Client-side hashing (password never transmitted) 2. PBKDF2 key stretching (slow brute force) 3. SHA-256 hashing (cannot reverse) 4. Salting (prevents rainbow tables) 5. TLS encryption (protects in transit) 6. Database encryption (protects at rest)
Result: Even if one layer fails, others protect.
Zero-Knowledge Architecture
Traditional: Server stores and can access your data
PVTLNK: Server never receives or stores your data
Result: Even with full database access, cannot identify users.
Privacy by Design
Traditional: Privacy added as feature
PVTLNK: Privacy designed from ground up
Result: Every design decision prioritizes privacy.
12. Industry Comparison
How We Compare to Major Services
| Service | Email Stored? | Password Transmitted? | IP Anonymized? | Zero-Knowledge? |
|---|---|---|---|---|
| Bitly | β Yes | β Yes | β No | β No |
| TinyURL | β Yes | β Yes | β No | β No |
| Rebrandly | β Yes | β Yes | β οΈ Partial | β No |
| PVTLNK | β NO | β NO | β YES | β YES |
Our Advantage: Only service with true zero-knowledge architecture.
13. Conclusion
Why Our Encryption Architecture Is Best
- Right Tool for Each Job:
- SHA-256 for hashing (one-way, fast)
- PBKDF2 for commitments (key stretching)
- BCrypt for passwords (adaptive hashing)
- AES-256 for database (bulk encryption)
- TLS 1.3 for traffic (hybrid encryption)
- Multiple Layers of Security:
- Client-side processing (data never transmitted)
- Key stretching (slow brute force)
- One-way hashing (cannot reverse)
- Salting (prevents rainbow tables)
- Traffic encryption (TLS)
- Database encryption (at rest)
- Zero-Knowledge Architecture:
- Username never stored or transmitted (only hash-derived nonce, client-side only)
- Password never stored or transmitted (only commitment hash)
- IP never stored in plain text (only hash with salt)
- Email addresses never collected or stored
- Cannot identify users (no personal data stored)
- Privacy by Design:
- Swiss hosting (legal protections)
- Client-side processing (data stays in browser)
- Anonymous by default (no identifiers)
- Tor support (maximum anonymity)
- World-Class Standards:
- NIST compliant (SHA-256, PBKDF2, AES-256)
- OWASP compliant (all recommendations met)
- Industry best practices (exceeds standards)
14. Technical Verification
How to Verify Our Claims
Code Review:
- Check app/views/auth/signup.html.erb - PBKDF2 client-side
- Check app/models/click_analytic.rb - SHA-256 + salt for IP
- Check app/controllers/api/auth_controller.rb - No email parameter
- Check db/schema.rb - No email column in commitment_users
Security Audit:
- Run test_privacy_whitepaper.rb - All privacy claims verified
- Run security_audit.rb - No backdoors or vulnerabilities
- Check NIST/OWASP compliance - All standards met
Database Inspection:
- Inspect commitment_users table - Only hashes, no emails
- Inspect click_analytics table - Only hashed IPs, no plain IPs
- Verify encryption - Exoscale AES-256 confirmed
15. Frequently Asked Questions
Q: Why PBKDF2 instead of Argon2?
A: PBKDF2 is: - β Native browser support (no polyfills needed) - β NIST-recommended (still secure) - β Sufficient security (100k iterations) - β Simpler implementation
Argon2 would be slightly stronger, but PBKDF2 provides adequate security for our needs.
Q: Can SHA-256 be reversed with quantum computers?
A: SHA-256 remains secure against quantum computers: - Quantum computers speed up some operations, but SHA-256 is still secure - Even with quantum speedup, 2^256 possibilities remain computationally infeasible - By the time quantum computers threaten SHA-256, weβll have upgraded (likely to SHA-3)
Current Status: SHA-256 secure for decades.
Q: Why not use end-to-end encryption?
A: We use zero-knowledge architecture instead: - End-to-End: Encrypts data, but server can still decrypt with keys - Zero-Knowledge: Server never receives data (cannot decrypt what it doesnβt have)
Our Approach: Better than end-to-end - server cannot access data even with keys.
Q: Is PBKDF2 secure enough?
A: Yes, PBKDF2 with 100k iterations is: - β NIST-recommended (SP 800-132) - β Industry standard (used by many major services) - β Secure against brute force (100,000x slower) - β Sufficient for commitments (not passwords)
For Passwords: We use BCrypt (specifically designed for passwords)
For Commitments: We use PBKDF2 (designed for key derivation)
Q: Can you see my IP address?
A: No, we: 1. Use your IP temporarily for geolocation (in-memory) 2. Immediately hash it with SHA-256 + salt 3. Store only the hash (original IP discarded) 4. Hash cannot be reversed (mathematical impossibility)
Result: We cannot determine your IP from stored data.
Q: What if youβre forced to hand over data?
A: We can only hand over: - Commitment hashes (cannot identify users) - Nonce hashes (cannot reveal emails) - Hashed IPs (cannot reverse) - Country-level data (too vague to identify)
Result: Even with legal order, we cannot identify users.
16. Appendix: Cryptographic Algorithms Reference
SHA-256
Type: Cryptographic Hash Function
Output: 256 bits (64 hex characters)
Security: Cryptographically secure, one-way
Use Cases: Data integrity, hashing, commitments
Our Use: IP anonymization, nonce generation, visitor fingerprinting
Why Secure: - One-way function (cannot reverse) - 2^256 possible outputs - No known practical attacks - Used by Bitcoin, TLS
PBKDF2
Type: Key Derivation Function
Iterations: 100,000
Hash Function: SHA-256
Output: 256 bits (64 hex characters)
Our Use: Commitment generation (client-side)
Why Secure: - Key stretching (100k iterations = 100,000x slower) - NIST-recommended (SP 800-132) - Designed for password-derived keys - Slows brute force attacks
BCrypt
Type: Password Hashing Function
Cost Factor: Adaptive (can increase over time)
Output: Includes salt and cost factor
Our Use: Link password protection
Why Secure: - Adaptive hashing (slows with time) - Automatic salting (unique per password) - Industry standard for passwords - Intentionally slow (prevents brute force)
AES-256
Type: Symmetric Encryption
Key Size: 256 bits
Our Use: Database encryption at rest (via Exoscale)
Why Secure: - Industry standard (used by governments, banks) - 2^256 possible keys (computationally infeasible) - Hardware accelerated (fast on modern CPUs) - No practical vulnerabilities
TLS 1.3
Type: Hybrid Encryption (Asymmetric + Symmetric)
Our Use: All network traffic (HTTPS)
Why Secure: - Latest TLS standard (most secure) - Perfect Forward Secrecy (unique keys per connection) - Certificate verification (prevents MITM) - Industry standard (used by all major websites)
Conclusion
PVTLNKβs encryption architecture is superior to traditional systems because:
- β Right Tools: Each cryptographic method chosen for specific purpose
- β Multiple Layers: 6+ layers of security (defense in depth)
- β Zero-Knowledge: Server never receives or stores personal data
- β Privacy by Design: Every decision prioritizes privacy
- β World-Class Standards: NIST, OWASP compliant
- β Mathematical Security: Privacy not by promise, but by impossibility
Result: Even we, the developers, cannot access your data because we never stored it in the first place.
17. Additional Security Features
Tor Support & Detection
Implementation: - Tor request detection (via IP ranges, headers, user agent analysis) - Privacy-preserving analytics for Tor users - Logged separately for privacy-focused analytics - No discrimination against Tor users
Privacy Impact: ββββ HIGH - Supports maximum anonymity users
Certificate Transparency Monitoring
Implementation: - Rake task to monitor SSL certificate issuance - Detects unauthorized certificate issuance (MITM protection) - Alerts on suspicious certificate activity
Security Impact: ββββ HIGH - Prevents man-in-the-middle via certificate attacks
CSP Violation Reporting
Implementation:
- Content Security Policy with nonces (prevents XSS)
- Violation reporting endpoint (/csp-violations/report)
- Automatic logging and monitoring
- Pattern detection for repeated XSS attempts
- Auto-blocking of malicious IPs (50+ violations)
Security Impact: βββββ VERY HIGH - Real-time XSS detection and prevention
Expect-CT Header
Implementation: - Certificate Transparency monitoring enforcement - Configured in production only - Provides additional MITM protection
Security Impact: βββ MEDIUM - Additional certificate verification layer
Swiss Hosting
Legal Privacy Protection: - Data stored in Switzerland (ch-dk-2 zone) - Subject to Swiss Federal Data Protection Act (FADP) - GDPR-equivalent standards - Not subject to foreign surveillance laws - Strong legal privacy protections
Privacy Impact: βββββ VERY HIGH - Legal layer of privacy protection
18. Storage Architecture
Instance Disk Encryption
What: - Exoscale instance disks encrypted at rest with AES-256 - Automatic (no configuration required) - Applies to all storage on instance disk
Whatβs Encrypted: - β Database files (SQLite database) - β Application code - β Logs - β All data on instance disk
Whatβs Not Encrypted (Application-Level): - URLs stored in plain text (required for link redirection functionality) - Link metadata (short codes, expiration dates, etc.)
Why URLs Arenβt Encrypted at Application Level: - Link redirection requires application to read destination URLs - Encrypting URLs would require decryption on every request - Database encryption at rest protects against physical access - Zero-knowledge authentication ensures username/password never stored - IP addresses hashed before storage
Security Model: - Infrastructure Level: All storage encrypted (AES-256) - Application Level: Only non-sensitive data in plain text (URLs needed for functionality) - Privacy Level: No personal identifiers stored (zero-knowledge authentication) - Analytics Level: IP addresses hashed, only country-level geolocation
19. Glossary & Key Terms
Commitment Hash: The cryptographic output of your password + nonce, created using PBKDF2. Used to authenticate you without storing or transmitting your password.
Deterministic Nonce: A βnumber used onceβ that is generated consistently from your username hash. Ensures the same username always produces the same nonce for consistent authentication.
Key Stretching (PBKDF2): A technique that intentionally slows down hashing via 100,000+ iterations to drastically increase the time and cost of brute-force attacks.
SHA-256: A cryptographic hash function that converts any input into a unique, fixed-length 256-bit (64-character hex) output. Mathematically one-way (cannot be reversed).
Zero-Knowledge Architecture: A system where the server can verify your identity without ever receiving or storing your username or password. Only cryptographic commitments are stored.
20. Relationship to Privacy Whitepaper
This Document (Encryption Architecture Guide): - Focuses on HOW we encrypt and hash data - Explains WHY we chose each cryptographic method - Provides technical deep dives and implementation details - Explains the mathematical and practical security of each layer
Privacy Whitepaper (Privacy & Security Whitepaper): - Focuses on WHAT data we protect - Explains WHY privacy matters - Provides user-facing explanations - Describes legal protections and guarantees
Together: These documents provide complete transparency - both technical (how) and practical (what/why).
Document Version: 2.0
Last Updated: November 2nd, 2025
Status: Technical reference document - Aligned with Privacy Whitepaper v2.2