Encryption Architecture Guide

Public Document β€’ Documentation

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


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


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

  1. 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)
  2. 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)
  3. 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)
  4. Privacy by Design:
    • Swiss hosting (legal protections)
    • Client-side processing (data stays in browser)
    • Anonymous by default (no identifiers)
    • Tor support (maximum anonymity)
  5. 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:

  1. βœ… Right Tools: Each cryptographic method chosen for specific purpose
  2. βœ… Multiple Layers: 6+ layers of security (defense in depth)
  3. βœ… Zero-Knowledge: Server never receives or stores personal data
  4. βœ… Privacy by Design: Every decision prioritizes privacy
  5. βœ… World-Class Standards: NIST, OWASP compliant
  6. βœ… 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