Building a Zero-Knowledge P2P File Sharing System: A Technical Deep Dive

Building a Zero-Knowledge P2P File Sharing System: A Technical Deep Dive

Traditional file sharing services like Google Drive, Dropbox, and WeTransfer all share a fundamental flaw: your files pass through their servers. Even with "encryption," these services hold the keys. We built something different—a peer-to-peer file sharing system where files transfer directly between browsers, encrypted end-to-end, with zero server-side storage. Here's exactly how it works.

The Problem with Traditional File Sharing

When you upload a file to a traditional service, it follows this path:

┌──────────────┐      ┌──────────────┐      ┌──────────────┐
│    Your      │      │   Provider   │      │  Recipient   │
│   Browser    │ ───► │   Servers    │ ───► │   Browser    │
└──────────────┘      └──────────────┘      └──────────────┘
                            │
                            ▼
                      Files stored,
                      accessible by
                      the provider

This architecture creates several vulnerabilities:

  1. Server Access: The provider can access your files
  2. Data Breaches: Stored files are targets for hackers
  3. Legal Requests: Governments can compel providers to hand over data
  4. Metadata Leakage: Upload times, file names, and access patterns are logged
  5. Permanent Storage: Files may persist indefinitely on their servers

Our Architecture: True Peer-to-Peer

Private File Share eliminates the server from the file transfer path entirely:

┌──────────────┐                              ┌──────────────┐
│    Your      │◄────── Direct P2P ──────────►│  Recipient   │
│   Browser    │       (WebRTC Data)          │   Browser    │
└──────────────┘                              └──────────────┘
       │                                             │
       │            ┌──────────────┐                 │
       └───────────►│   Signaling  │◄────────────────┘
                    │    Server    │
                    └──────────────┘
                           │
                    Only coordinates
                    the connection,
                    NEVER sees files

The server's sole purpose is to help two browsers find each other. Once the WebRTC connection is established, files flow directly between browsers—encrypted before they leave your device.

Technical Architecture Overview


The Four Pillars of Our System

┌──────────────────────────────────────────────────────────────────────┐
│                        FILE SHARE                                    │
├─────────────────┬─────────────────┬────────────────┬─────────────────┤
│   ENCRYPTION    │    CHUNKING     │    WEBRTC      │   SIGNALING     │
├─────────────────┼─────────────────┼────────────────┼─────────────────┤
│ • AES-256-CBC   │ • 64KB chunks   │ • P2P connect  │ • Room mgmt     │
│ • PBKDF2 keys   │ • Progress track│ • Data channel │ • Peer discovery│
│ • SHA256 verify │ • Reassembly    │ • Binary xfer  │ • Auto-cleanup  │
└─────────────────┴─────────────────┴────────────────┴─────────────────┘

Encryption: Military-Grade Protection

Why AES-256-CBC with PBKDF2?

We chose this combination for maximum security:

ComponentPurposeSecurity Benefit
AES-256Encryption algorithm2^256 possible keys—virtually unbreakable
CBC ModeBlock chainingEach block depends on previous, preventing patterns
PBKDF2Key derivationProtects weak passwords through 10,000 iterations
Random SaltPer-encryption uniquenessPrevents rainbow table attacks
Random IVInitialization vectorSame file encrypts differently each time

The Encryption Flow

┌─────────────────────────────────────────────────────────────────────┐
│                     ENCRYPTION PROCESS                              │
└─────────────────────────────────────────────────────────────────────┘

Step 1: Key Derivation
┌──────────┐    ┌─────────────┐    ┌──────────────┐
│ Password │ +  │ Random Salt │ ─► │   PBKDF2     │ ─► 256-bit Key
└──────────┘    │  (128-bit)  │    │ (10K rounds) │
                └─────────────┘    └──────────────┘

Step 2: Encryption
┌──────────┐    ┌───────────┐    ┌────────────────┐
│   File   │ +  │ 256-bit   │ +  │  Random IV     │ ─► Encrypted Data
│   Data   │    │    Key    │    │  (128-bit)     │
└──────────┘    └───────────┘    └────────────────┘

Step 3: Package for Transfer
┌────────────────────────────────────────────────────┐
│  Salt (16B)  │  IV (16B)  │  Encrypted Content     │
└────────────────────────────────────────────────────┘
         ▲            ▲                 ▲
         │            │                 │
    For key      For decrypt     Your protected
    derivation   initialization       data

Decryption (Receiver Side)

┌─────────────────────────────────────────────────────────────────────┐
│                     DECRYPTION PROCESS                              │
└─────────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────┐
│  Salt (16B)  │  IV (16B)  │  Encrypted Content     │
└──────┬───────┴─────┬──────┴──────────┬─────────────┘
       │             │                 │
       ▼             │                 │
┌──────────────┐     │                 │
│  + Password  │     │                 │
│      ▼       │     │                 │
│   PBKDF2     │     │                 │
│      ▼       │     │                 │
│  256-bit Key │─────┼─────────────────┤
└──────────────┘     │                 │
                     ▼                 ▼
              ┌─────────────────────────────┐
              │     AES-256 Decryption      │
              └──────────────┬──────────────┘
                             ▼
                    ┌─────────────────┐
                    │  Original File  │
                    └─────────────────┘

Cryptographic Properties Summary

PropertyValueWhy It Matters
Key Size256 bitsWould take billions of years to brute force
Salt128 bits, randomEvery encryption is unique
IV128 bits, randomIdentical files produce different ciphertext
Iterations10,000 PBKDF2Slows brute force attacks by 10,000x
ChecksumSHA-256Guarantees file integrity after transfer

File Chunking: Reliable Large File Transfer

WebRTC data channels work best with smaller packets. We split files into manageable pieces:

Why 64KB Chunks?

┌─────────────────────────────────────────────────────────────────────┐
│                    CHUNKING STRATEGY                                │
└─────────────────────────────────────────────────────────────────────┘

Original File (e.g., 10 MB)
┌─────────────────────────────────────────────────────────────────────┐
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
└─────────────────────────────────────────────────────────────────────┘
                              │
                              ▼ Split into 64KB chunks
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐        ┌─────┐
│  1  │ │  2  │ │  3  │ │  4  │ │  5  │  ...   │ 160 │
│64KB │ │64KB │ │64KB │ │64KB │ │64KB │        │64KB │
└─────┘ └─────┘ └─────┘ └─────┘ └─────┘        └─────┘
   │       │       │       │       │              │
   └───────┴───────┴───────┴───────┴──────────────┘
                         │
                         ▼
            Each chunk sent via WebRTC
            with sequence number for
            proper reassembly

Benefits of This Approach

BenefitExplanation
ReliabilitySmaller packets transfer more reliably over WebRTC
Progress TrackingUsers see real-time progress (every 64KB)
Memory EfficiencyDoesn't require loading entire file into RAM
Error RecoveryEasier to retry a 64KB chunk than a 500MB file

The Complete Transfer Pipeline

SENDER BROWSER                                      RECEIVER BROWSER
┌────────────────┐                                  ┌────────────────┐
│ 1. Select File │                                  │                │
│       ▼        │                                  │                │
│ 2. Encrypt     │                                  │                │
│    (AES-256)   │                                  │                │
│       ▼        │                                  │                │
│ 3. Chunk       │                                  │                │
│    (64KB each) │                                  │                │
│       ▼        │      WebRTC Data Channel         │       ▼        │
│ 4. Send ───────┼─────────────────────────────────►│ 5. Receive     │
│                │         (Direct P2P)             │       ▼        │
│                │                                  │ 6. Reassemble  │
│                │                                  │       ▼        │
│                │                                  │ 7. Verify      │
│                │                                  │    (SHA-256)   │
│                │                                  │       ▼        │
│                │                                  │ 8. Decrypt     │
│                │                                  │       ▼        │
│                │                                  │ 9. Download    │
└────────────────┘                                  └────────────────┘

WebRTC: The P2P Connection Layer

What is WebRTC?

WebRTC (Web Real-Time Communication) enables direct browser-to-browser connections without plugins. Originally designed for video calls, its data channels are perfect for file transfer.

The Connection Dance

┌─────────────────────────────────────────────────────────────────────┐
│                  WEBRTC CONNECTION ESTABLISHMENT                    │
└─────────────────────────────────────────────────────────────────────┘

    SENDER                    SERVER                    RECEIVER
      │                         │                          │
      │ 1. Create Room          │                          │
      │────────────────────────►│                          │
      │                         │                          │
      │   Room code: XY7K2M     │                          │
      │◄────────────────────────│                          │
      │                         │                          │
      │         (User shares code externally)              │
      │                         │                          │
      │                         │        2. Join Room      │
      │                         │◄─────────────────────────│
      │                         │                          │
      │  3. Peer Joined!        │                          │
      │◄────────────────────────│                          │
      │                         │                          │
      │ 4. WebRTC Offer         │                          │
      │────────────────────────►│─────────────────────────►│
      │                         │                          │
      │                         │     5. WebRTC Answer     │
      │◄────────────────────────│◄─────────────────────────│
      │                         │                          │
      │ 6. ICE Candidates       │    6. ICE Candidates     │
      │◄───────────────────────►│◄────────────────────────►│
      │                         │                          │
      ├─────────────────────────┼──────────────────────────┤
      │                         │                          │
      │     DIRECT P2P CONNECTION ESTABLISHED              │
      │◄══════════════════════════════════════════════════►│
      │                         │                          │
      │     Files transfer directly, server not involved   │
      │                         │                          │

ICE Servers: Finding the Path

We use STUN servers to help browsers discover their public addresses and find the best path to connect:

┌─────────────────────────────────────────────────────────────────────┐
│                      NETWORK PATH DISCOVERY                         │
└─────────────────────────────────────────────────────────────────────┘

┌──────────┐         ┌───────────────┐         ┌──────────┐
│  Sender  │────────►│ STUN Servers  │◄────────│ Receiver │
│  Browser │         │ (Google/Twilio)│         │  Browser │
└──────────┘         └───────────────┘         └──────────┘
     │                      │                        │
     │    "What's my        │      "What's my       │
     │    public IP?"       │       public IP?"     │
     │                      │                        │
     ▼                      ▼                        ▼
┌─────────────────────────────────────────────────────────────────┐
│            ICE candidates exchanged via signaling               │
│                                                                 │
│    Browsers find optimal path: direct, STUN-assisted, or TURN   │
└─────────────────────────────────────────────────────────────────┘

The Signaling Server: Minimal by Design

Our signaling server is intentionally simple—it coordinates connections but never touches file data.

What the Server Stores (In Memory Only)

┌─────────────────────────────────────────────────────────────────────┐
│                    ROOM DATA STRUCTURE                              │
└─────────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────┐
│ Room: XY7K2M                           │
├────────────────────────────────────────┤
│ • Password Hash (SHA-256)              │  ◄── Never the actual password
│ • Expiration Time                      │
│ • Max Downloads Allowed                │
│ • Current Download Count               │
│ • Connected Peer IDs                   │  ◄── Just socket IDs, no identity
│ • Created Timestamp                    │
└────────────────────────────────────────┘

        NEVER STORED:
        ✗ File contents
        ✗ File names
        ✗ File sizes
        ✗ Encryption keys
        ✗ Actual passwords
        ✗ User identities

What the Server NEVER Sees

┌─────────────────────────────────────────────────────────────────────┐
│               SERVER VISIBILITY COMPARISON                          │
└─────────────────────────────────────────────────────────────────────┘

                    TRADITIONAL              OUR DESIGNED
                    FILE SHARING             FILE SHARING

File Contents       ██████████ YES           ░░░░░░░░░░ NO
File Names          ██████████ YES           ░░░░░░░░░░ NO
File Sizes          ██████████ YES           ░░░░░░░░░░ NO
Encryption Keys     ██████████ YES           ░░░░░░░░░░ NO
User Identity       ██████████ YES           ░░░░░░░░░░ NO
Transfer Metadata   ██████████ YES           ░░░░░░░░░░ NO

Room Code           ░░░░░░░░░░ N/A           ██████████ YES
Password Hash       ░░░░░░░░░░ N/A           ██████████ YES
Expiration Time     ░░░░░░░░░░ N/A           ██████████ YES

Automatic Cleanup

┌─────────────────────────────────────────────────────────────────────┐
│                    AUTO-CLEANUP MECHANISMS                          │
└─────────────────────────────────────────────────────────────────────┘

1. EXPIRATION TIMER (per room)
   ┌─────────────────────────────────────────┐
   │ Room Created ──► Timer Started          │
   │                       │                 │
   │                  15min/30min/1hr/24hr   │
   │                       │                 │
   │                       ▼                 │
   │               Room Auto-Deleted         │
   └─────────────────────────────────────────┘

2. PERIODIC CLEANUP (every 5 minutes)
   ┌─────────────────────────────────────────┐
   │ Server scans all rooms                  │
   │         │                               │
   │         ▼                               │
   │ Removes any expired rooms               │
   │         │                               │
   │         ▼                               │
   │ Notifies connected peers                │
   └─────────────────────────────────────────┘

3. DISCONNECT CLEANUP
   ┌─────────────────────────────────────────┐
   │ All peers disconnect                    │
   │         │                               │
   │         ▼                               │
   │ Room immediately deleted                │
   │         │                               │
   │         ▼                               │
   │ No trace remains                        │
   └─────────────────────────────────────────┘

Security Features Beyond Encryption

Rate Limiting Protection

┌─────────────────────────────────────────────────────────────────────┐
│                    RATE LIMITING                                    │
└─────────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────┐
│ Per IP Address, Per Minute:            │
├────────────────────────────────────────┤
│ • Max 30 total requests                │
│ • Max 5 failed password attempts       │
│                                        │
│ Exceeds limit?                         │
│     ▼                                  │
│ Request rejected with error            │
│ Prevents brute force attacks           │
└────────────────────────────────────────┘

Input Validation

┌─────────────────────────────────────────────────────────────────────┐
│                    INPUT VALIDATION                                 │
└─────────────────────────────────────────────────────────────────────┘

Every input is validated before processing:

┌─────────────────┬──────────────────────────┬───────────────────────┐
│ Input           │ Validation Rule          │ Purpose               │
├─────────────────┼──────────────────────────┼───────────────────────┤
│ Room Code       │ Exactly 6 alphanumeric   │ Prevent injection     │
│ Password Hash   │ Valid SHA-256 format     │ Ensure proper hashing │
│ Expiration      │ Max 7 days               │ Limit resource usage  │
│ Max Downloads   │ Predefined values only   │ Prevent abuse         │
└─────────────────┴──────────────────────────┴───────────────────────┘

Download Limits

┌─────────────────────────────────────────────────────────────────────┐
│                    DOWNLOAD LIMIT ENFORCEMENT                       │
└─────────────────────────────────────────────────────────────────────┘

    Receiver attempts to join
              │
              ▼
    ┌─────────────────────┐
    │ Check download count │
    │ vs. max downloads    │
    └─────────────────────┘
              │
     ┌────────┴────────┐
     │                 │
     ▼                 ▼
┌─────────┐      ┌─────────────┐
│ Under   │      │ Limit       │
│ Limit   │      │ Reached     │
└────┬────┘      └──────┬──────┘
     │                  │
     ▼                  ▼
 Allow join        Reject with
 & increment       error message
 counter

How We Compare to Alternatives

┌─────────────────────────────────────────────────────────────────────┐
│                    FEATURE COMPARISON                               │
└─────────────────────────────────────────────────────────────────────┘

                    Our Design   WeTransfer   Google     OnionShare
                                            Drive
┌───────────────────┬──────────┬───────────┬─────────┬────────────┐
│ Server sees files │    NO    │    YES    │   YES   │     NO     │
├───────────────────┼──────────┼───────────┼─────────┼────────────┤
│ True E2E encrypt  │   YES    │    NO*    │   NO*   │    YES     │
├───────────────────┼──────────┼───────────┼─────────┼────────────┤
│ P2P transfer      │   YES    │    NO     │   NO    │    YES     │
├───────────────────┼──────────┼───────────┼─────────┼────────────┤
│ Requires software │    NO    │    NO     │   NO    │    YES     │
├───────────────────┼──────────┼───────────┼─────────┼────────────┤
│ Auto-delete       │   YES    │   YES     │   NO    │    YES     │
├───────────────────┼──────────┼───────────┼─────────┼────────────┤
│ Password protect  │   YES    │   PAID    │   YES   │    YES     │
├───────────────────┼──────────┼───────────┼─────────┼────────────┤
│ Download limits   │   YES    │   PAID    │   NO    │    YES     │
├───────────────────┼──────────┼───────────┼─────────┼────────────┤
│ No account needed │   YES    │   YES     │   NO    │    YES     │
├───────────────────┼──────────┼───────────┼─────────┼────────────┤
│ Max file size     │  500MB   │  2GB free │  15GB   │ Unlimited  │
└───────────────────┴──────────┴───────────┴─────────┴────────────┘

* These services offer encryption but hold the decryption keys themselves

Real-World Transfer Flow

Complete Sender Journey

┌─────────────────────────────────────────────────────────────────────┐
│                    SENDER EXPERIENCE                                │
└─────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ STEP 1: Select Files                                             │
│ ┌────────────────────────────────────────────────────────────┐   │
│ │     document.pdf (10 MB)                                   │   │
│ │     photo.jpg (2 MB)                                       │   │
│ └────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│ STEP 2: Configure Options                                        │
│ ┌────────────────────────────────────────────────────────────┐   │
│ │     Expiration: 30 minutes                                 │   │
│ │     Max Downloads: 5                                       │   │
│ │     Password: ••••••••                                     │   │
│ └────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│ STEP 3: Create Share Link                                        │
│ ┌────────────────────────────────────────────────────────────┐   │
│ │     Room Created!                                          │   │
│ │     Code: XY7K2M                                           │   │
│ │     Waiting for receiver...                                │   │
│ └────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│ STEP 4: Transfer (after receiver joins)                          │
│ ┌────────────────────────────────────────────────────────────┐   │
│ │     P2P Connected!                                         │   │
│ │     Sending: document.pdf                                  │   │
│ │  ████████████████████░░░░░░░░░░ 65%                        │   │
│ └────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘

Complete Receiver Journey

┌─────────────────────────────────────────────────────────────────────┐
│                    RECEIVER EXPERIENCE                              │
└─────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│ STEP 1: Enter Room Code                                          │
│ ┌────────────────────────────────────────────────────────────┐   │
│ │     Room Code: [ XY7K2M ]                                  │   │
│ │     Password:  [ •••••• ]                                  │   │
│ │     [Join Room]                                            │   │
│ └────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│ STEP 2: View Available Files                                     │
│ ┌────────────────────────────────────────────────────────────┐   │
│ │     document.pdf (10 MB)                                   │   │
│ │     photo.jpg (2 MB)                                       │   │
│ │  [Download Selected]                                       │   │
│ └────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────────────────────────────────────────────────────────┐
│ STEP 3: Download                                                 │
│ ┌────────────────────────────────────────────────────────────┐   │
│ │     Receiving: document.pdf                                │   │
│ │  ████████████████████████████ 100%                         │   │
│ │     Checksum verified                                      │   │
│ │     Decrypted successfully                                 │   │
│ │     Saved to Downloads                                     │   │
│ └────────────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────────────┘

Performance Considerations

Transfer Speed Expectations

┌─────────────────────────────────────────────────────────────────────┐
│                    TYPICAL TRANSFER SPEEDS                          │
└─────────────────────────────────────────────────────────────────────┘

Network Scenario                    Expected Speed
─────────────────────────────────────────────────────────────────────
Same local network                  Near wire speed (100+ Mbps)
Same ISP                            50-100 Mbps typical
Cross-country                       10-50 Mbps typical
International                       5-20 Mbps typical

Note: Actual speeds depend on both parties' connections and network path

File Size Limits

┌─────────────────────────────────────────────────────────────────────┐
│                    SIZE CONSTRAINTS                                 │
└─────────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────┐
│ Per File Maximum:        500 MB        │
│ Per Session Maximum:     1 GB total    │
│ Chunk Size:              64 KB         │
└────────────────────────────────────────┘

Why these limits?
• Browser memory constraints
• WebRTC reliability
• User experience (reasonable wait times)

The Security Guarantee

What Makes This Truly Zero-Knowledge

┌─────────────────────────────────────────────────────────────────────┐
│                    ZERO-KNOWLEDGE ARCHITECTURE                      │
└─────────────────────────────────────────────────────────────────────┘

                    SENDER                    RECEIVER
                    BROWSER                   BROWSER
                       │                         │
    ┌──────────────────┴──────────────────┬──────┴────────────────────┐
    │                                     │                           │
    ▼                                     ▼                           ▼
┌───────────┐                        ┌────────┐                 ┌───────────┐
│ Encryption│                        │Signaling│                 │ Decryption│
│ happens   │                        │  Only   │                 │ happens   │
│ HERE      │                        │         │                 │ HERE      │
└───────────┘                        └────────┘                 └───────────┘
                                          │
                                          ▼
                                    ┌───────────┐
                                    │  Server   │
                                    │  CANNOT:  │
                                    │           │
                                    │ • Read    │
                                    │   files   │
                                    │           │
                                    │ • Decrypt │
                                    │   content │
                                    │           │
                                    │ • Access  │
                                    │   keys    │
                                    └───────────┘

Even If Compromised...

┌─────────────────────────────────────────────────────────────────────┐
│            WHAT AN ATTACKER WOULD FIND                              │
└─────────────────────────────────────────────────────────────────────┘

If our server was completely compromised, an attacker would find:

✗ No files (they never touch our server)
✗ No encryption keys (generated and used only in browsers)
✗ No passwords (only hashes, and only for room authentication)
✗ No user identities (no accounts required)
✗ No transfer history (rooms auto-delete)

Only:
✓ Temporary room metadata
✓ WebRTC signaling data (useless without the actual connection)

Conclusion: Privacy Through Architecture

The most secure system is one where even the operator cannot access your data. By using:

  • Client-side encryption: Files encrypted before leaving your browser
  • P2P transfer: Files never touch our servers
  • In-memory signaling: No persistent storage
  • Automatic cleanup: Rooms self-destruct

We've built a file sharing system that is private by design, not by policy. Even if our servers were compromised, attackers would find only WebRTC signaling data—no files, no encryption keys, no metadata.

This is the future of file sharing: zero knowledge, zero trust, zero compromise.

Akshat Joshi

Akshat Joshi

Senior Technical Specialist
Washington DC