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:
- Server Access: The provider can access your files
- Data Breaches: Stored files are targets for hackers
- Legal Requests: Governments can compel providers to hand over data
- Metadata Leakage: Upload times, file names, and access patterns are logged
- 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:
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
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
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.