The Null Drop: Anonymous File Sharing in C
π Before You Read
These are personal research notes β a record of something I built and found worth documenting. I explain the core ideas and design choices, but this is not a step-by-step guide, a support thread, or a turnkey implementation.
This blog is my lab notebook.
β οΈ Source code is intentionally incomplete. Snippets are illustrative and will not compile or run as-is.
Disclaimer
This material is provided strictly for educational and ethical security research purposes.
By continuing, you agree that:
- You are solely responsible for how you use this information.
- You will not apply it for illegal, unauthorized, or malicious activity.
- The author assumes no liability for misuse or damages resulting from its application.
Do not use this knowledge to access systems without permission, disrupt services, collect data unlawfully, or violate applicable cybersecurity or privacy laws in your jurisdiction.
The intent is to advance defensive understanding, privacy awareness, and ethical research β nothing more.
Proceed responsibly.
Table of Contents
- Overview
- How TOR Works
- What "Your IP Never Reaches the Server" Means
- AES-256 Encryption
- 0x0.st β The File Host
- The Full Security Stack
- C Implementation
- Setup & Usage
- Threat Model
- Latency & Trade-offs
- Key Concepts Glossary
- References
- Final Thoughts
1. Overview
This system combines three independent components to achieve anonymous, encrypted file sharing:
| Component | Role | Protects Against |
|---|---|---|
| AES-256-CBC | Encrypts file content | Anyone reading the file |
| TOR Network | Hides your IP address | Server knowing who you are |
| 0x0.st | Hosts the encrypted blob | Need to run your own server |
| PBKDF2-SHA256 | Hardens the password | Brute-force attacks |
The key principle: no single point of failure. Even if someone compromises 0x0.st, they only see encrypted ciphertext. Even if they break the encryption, they cannot trace who uploaded it because TOR hid the uploader's IP.
2. How TOR Works
TOR (The Onion Router) routes your traffic through three volunteer-operated nodes before reaching the destination. Each node only knows the previous and next hop β never the full path.
The 3-Hop Circuit
βββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β YOU β β Guard Node β β Middle Node β β Exit Node β
β 103.45.67.x ββββββΆβ Germany ββββββΆβ Netherlands ββββββΆβ Romania β
β β β β β β β β
β Knows: β β Knows: β β Knows: β β Knows: β
β - Guard IP β β - Your IP β β - Guard IP β β - Middle IP β
β β β - Middle IP β β - Exit IP β β - Dest. IP β
β β β NOT dest. β β NOT you β β NOT you β
βββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β
βΌ
0x0.st
Sees: Romania IP only
Onion Encryption Layers
Before sending, your TOR client wraps the data in three layers of encryption β one for each node:
Original Data
βββ Encrypted for Exit Node β Exit node decrypts this layer
βββ Encrypted for Middle Node β Middle node decrypts this layer
βββ Encrypted for Guard β Guard node decrypts this layer
Each node peels one layer, like peeling an onion β hence the name.
Why No Single Node Can Betray You
| Node | Knows Your IP? | Knows Destination? |
|---|---|---|
| Guard Node | β Yes | β No |
| Middle Node | β No | β No |
| Exit Node | β No | β Yes |
No single node has both pieces of information simultaneously.
3. What "Your IP Never Reaches the Server" Means
Without TOR β Direct Connection
Your PC βββββββββββββββββββββββββββββββββββββββΆ 0x0.st
IP: 103.45.67.89 Logs: 103.45.67.89
ISP also logs this connection
The server's access log records your real IP. Law enforcement can subpoena these logs. Your ISP also sees the destination.
With TOR β Anonymized Connection
Your PC βββΆ Guard βββΆ Middle βββΆ Exit βββΆ 0x0.st
103.45.67.89 185.220.x.x Logs: 185.220.x.x (Exit node)
0x0.st logs the exit node's IP, which is a volunteer's server β not yours. Your real IP 103.45.67.89 never appears in any request to the destination server.
DNS Leak Prevention β socks5h:// vs socks5://
This is a critical implementation detail:
// β WRONG β DNS resolved locally (leaks hostnames to your ISP)
#define TOR_PROXY "socks5://127.0.0.1:9050"
// β
CORRECT β DNS resolved inside TOR (no leak)
#define TOR_PROXY "socks5h://127.0.0.1:9050"
// ^
// h = hostname resolution through TOR
Without socks5h, your system sends DNS queries for 0x0.st to your ISP's DNS server before connecting through TOR. This reveals which sites you're visiting even if the content is hidden.
4. AES-256 Encryption
What is AES-256-CBC?
AES (Advanced Encryption Standard) with a 256-bit key in CBC (Cipher Block Chaining) mode is a symmetric encryption algorithm used by governments, militaries, and financial institutions worldwide.
- 256-bit key = 2Β²β΅βΆ possible keys β more combinations than atoms in the observable universe
- CBC mode = each block of ciphertext depends on the previous block, preventing pattern analysis
- Block size = 16 bytes (128-bit)
Key Derivation β PBKDF2-SHA256
A human password like "hunter2" is too short and weak to use directly as an AES key. PBKDF2 (Password-Based Key Derivation Function 2) solves this:
Password: "hunter2" + Random Salt (16 bytes)
β
PBKDF2-SHA256 Γ 200,000 iterations
β
AES-256 Key (32 bytes) β looks like random data
The 200,000 iterations mean an attacker trying to brute-force the password must run the hash function 200,000 times per guess. At 1 billion guesses/second, cracking a 12-character random password would take longer than the age of the universe.
The Encrypted Blob Structure
The program stores all decryption metadata alongside the ciphertext in a single binary blob:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BLOB HEADER (fixed size) β
β ββββββββββββ¬βββββββββββββββ¬βββββββββββ¬ββββββββββββββββ β
β β Magic β Salt β IV β Lengths β β
β β "0X0E" β 16 bytes β 16 bytes β 8+8 bytes β β
β β 4 bytes β (random) β (random) β β β
β ββββββββββββ΄βββββββββββββββ΄βββββββββββ΄ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β CIPHERTEXT (variable size) β
β [ encrypted file data ... ] β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Field | Purpose |
|---|---|
| Magic | Identifies the blob format (0X0E) |
| Salt | Random value β makes each encryption unique even with same password |
| IV | Initialization Vector β randomizes CBC mode |
| Lengths | Needed to correctly decrypt and verify output size |
| Ciphertext | The actual encrypted file data |
5. 0x0.st β The File Host
0x0.st (the "null pointer") is a minimalist file hosting service:
- No account required β completely anonymous uploads
- Simple HTTP POST β upload with a single
curlcommand - Returns a URL β direct link to your file
- Returns
X-Tokenheader β a secret token that lets you delete the file later - File retention β files are kept based on size (larger files expire sooner)
Upload API
# Upload any file
curl -F "file=@myfile.bin" https://0x0.st
# Response:
# https://0x0.st/AbCd.bin
# X-Token: secrettoken123
Delete API
# Delete using token
curl -F "token=secrettoken123" -F "delete=" https://0x0.st/AbCd.bin
Why 0x0.st Over PasteBin?
| Feature | 0x0.st | PasteBin |
|---|---|---|
| API Key Required | β No | β Yes |
| Binary file support | β Yes | β No (text only) |
| Deletion token | β
Yes (X-Token) |
β οΈ Limited |
| Account needed | β No | Optional |
| Size limit | ~512 MB | ~10 MB |
Binary support is critical here β our encrypted blob is raw binary data, not text.
6. The Full Security Stack
Encryption Flow (Upload)
Original File
β
βΌ
βββββββββββββββββββββββββββββββββββ
β 1. Generate random Salt + IV β (RAND_bytes β cryptographically secure)
β 2. Derive AES key via PBKDF2 β (password + salt β 32-byte key)
β 3. AES-256-CBC encrypt β (plaintext β ciphertext)
β 4. Prepend blob header β (salt, iv, lengths)
β 5. Write binary blob to temp β
βββββββββββββββββββββββββββββββββββ
β
βΌ
Encrypted Blob (binary)
β
βΌ
βββββββββββββββββββββββββββββββββββ
β 6. CURL multipart POST β
β 7. Via SOCKS5h β TOR daemon β (127.0.0.1:9050)
β 8. TOR 3-hop circuit β (Guard β Middle β Exit)
β 9. Exit node β 0x0.st β
βββββββββββββββββββββββββββββββββββ
β
βΌ
URL + Token (stored in receipt.txt)
Decryption Flow (Download)
URL + AES Password
β
βΌ
βββββββββββββββββββββββββββββββββββ
β 1. CURL GET via TOR β (anonymous download)
β 2. Verify magic bytes "0X0E" β
β 3. Extract salt, IV, lengths β
β 4. Derive AES key via PBKDF2 β (same password + stored salt)
β 5. AES-256-CBC decrypt β
β 6. Verify plaintext length β
β 7. Write to output file β
βββββββββββββββββββββββββββββββββββ
β
βΌ
Original File (restored)
7. C Implementation
Core CURL TOR Setup
The most important function β applies TOR proxy to every network request:
static CURL *curl_tor_init(void) {
CURL *curl = curl_easy_init();
// Route ALL traffic through TOR SOCKS5h proxy
curl_easy_setopt(curl, CURLOPT_PROXY, "socks5h://127.0.0.1:9050");
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
// Security settings
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); // Verify TLS cert
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); // Verify hostname
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120L); // TOR is slower
curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.88.0"); // Generic UA
return curl;
}
Key Derivation
static int derive_key(const char *pass, const unsigned char *salt,
unsigned char *key) {
return PKCS5_PBKDF2_HMAC(
pass, strlen(pass), // Password
salt, SALT_LEN, // Random salt (16 bytes)
200000, // 200,000 iterations
EVP_sha256(), // Hash function
AES_KEY_LEN, // Output: 32 bytes
key
);
}
TOR Verification
The program can verify TOR is working before uploading:
// Hits https://check.torproject.org/api/ip
// Returns: {"IsTor":true,"IP":"185.220.x.x"}
Compile
# Install dependencies
sudo apt install libssl-dev libcurl4-openssl-dev
# Compile
gcc secure_0x0_tor.c -o secure_0x0_tor -lssl -lcrypto -lcurl
8. Setup & Usage
Step 1 β Install and Start TOR
# Install TOR
sudo apt install tor # Debian/Ubuntu
brew install tor # macOS
# Start the daemon
sudo systemctl start tor
sudo systemctl enable tor # Auto-start on boot
# Verify TOR is listening on port 9050
ss -tlnp | grep 9050
Step 2 β Verify TOR Connection
./secure_0x0_tor check
# Expected output:
# [+] Response: {"IsTor":true,"IP":"185.220.101.x"}
# ββββββββββββββββββββββββββββββββββββββββββββ
# β β Connected through TOR network β
# β Your real IP is hidden β
# ββββββββββββββββββββββββββββββββββββββββββββ
Step 3 β Encrypt & Upload
./secure_0x0_tor encrypt secret.pdf "my-strong-password"
# Output:
# [+] Read 42391 bytes from 'secret.pdf'
# [+] Key derived (PBKDF2-SHA256, 200k rounds)
# [+] Encrypted 42391 β 42400 bytes
# [+] Uploading via TOR β https://0x0.st ...
#
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# β UPLOAD SUCCESSFUL (via TOR) β β
# β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
# β URL : https://0x0.st/AbCdEfGh.bin β
# β Token : a1b2c3d4e5f6... β
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Step 4 β Share With Recipient
Share these three things separately (never together in one message):
1. URL β https://0x0.st/AbCdEfGh.bin (can send openly)
2. Token β a1b2c3d4... (keep private β for deletion)
3. Password β "my-strong-password" (send via Signal or in person)
Step 5 β Recipient Decrypts
./secure_0x0_tor decrypt https://0x0.st/AbCdEfGh.bin "my-strong-password"
# Output file: decrypted_AbCdEfGh.bin
Step 6 β Delete After Use
./secure_0x0_tor delete https://0x0.st/AbCdEfGh.bin "a1b2c3d4e5f6..."
# HTTP 200 β Deleted successfully
9. Threat Model
What This System Protects Against
| Threat | Protected? | How |
|---|---|---|
| 0x0.st seeing your IP | β Yes | TOR exit node IP shown instead |
| ISP seeing destination | β Yes | TOR encrypts traffic |
| Network surveillance / MITM | β Yes | TOR + TLS |
| Server compromise β reading files | β Yes | AES-256 ciphertext only |
| Passive global traffic analysis | β οΈ Partial | TOR reduces but doesn't eliminate |
| Someone with your URL but no password | β Yes | AES-256 encryption |
| DNS leaks | β Yes | socks5h:// resolves DNS inside TOR |
What This System Does NOT Protect Against
| Threat | Protected? | Notes |
|---|---|---|
| Malware on your own machine | β No | Keylogger can steal password |
| Weak AES password | β No | Use 12+ random characters |
| Operational security mistakes | β No | Logging in to accounts while using TOR |
| Advanced timing attacks | β No | Nation-state level adversaries |
| Physical access to your machine | β No | Disk forensics can find temp files |
Password Strength Recommendations
| Password | Time to Crack (200k PBKDF2) | Rating |
|---|---|---|
password123 |
Seconds | β Never use |
correct-horse-battery |
Years | β οΈ Passable |
Xk9#mP2$vL7nQ4@ |
Heat death of universe | β Excellent |
| Random 20-char alphanumeric | Heat death of universe | β Excellent |
10. Latency & Trade-offs
Why TOR is Slower
Your data travels through 3 servers across the world instead of going directly:
Direct connection:
You βββββββββββββββββββββββββββββββ 0x0.st
Latency: ~50ms
TOR connection:
You ββ Germany ββ Netherlands ββ Romania ββ 0x0.st
Latency: ~2000ms (40Γ slower)
Each hop adds:
- Physical distance β packets crossing continents multiple times
- Encryption overhead β each node encrypts/decrypts one layer
- Volunteer hardware β TOR nodes are not enterprise data centers
- Circuit setup β TOR negotiates keys with all 3 nodes before sending data
File Upload Time Estimates
| File Size | Direct | Via TOR |
|---|---|---|
| 10 KB | < 1 sec | 5β15 sec |
| 100 KB | 1β2 sec | 15β30 sec |
| 512 KB (our limit) | 2β5 sec | 30β90 sec |
The Trade-off is Worth It
The latency cost is entirely acceptable for sensitive file sharing where anonymity matters. For real-time streaming or large files, TOR is the wrong tool β but for occasional secure uploads, 30β90 seconds is a small price for hiding your identity completely.
11. Key Concepts Glossary
| Term | Definition |
|---|---|
| AES | Advanced Encryption Standard β symmetric block cipher used worldwide |
| CBC | Cipher Block Chaining β each ciphertext block depends on the previous |
| PBKDF2 | Password-Based Key Derivation Function 2 β stretches weak passwords into strong keys |
| Salt | Random bytes added to password before hashing β prevents rainbow table attacks |
| IV | Initialization Vector β random value that randomizes the first CBC block |
| TOR | The Onion Router β anonymity network routing traffic through 3 hops |
| Exit Node | The last TOR hop β the IP address the destination server sees |
| SOCKS5h | Proxy protocol where DNS resolution happens on the proxy side (inside TOR) |
| DNS Leak | When DNS queries bypass TOR, revealing which sites you visit to your ISP |
| 0x0.st | Minimalist anonymous file host β no account, returns URL + delete token |
| X-Token | HTTP response header from 0x0.st containing the file deletion secret |
| Blob | Binary data structure combining the encrypted blob header and ciphertext |
| Multipart POST | HTTP file upload format used to send binary files to 0x0.st |
| CURLOPT_PROXYTYPE | libcurl option specifying the proxy protocol type |
12. References
- TOR Project β Official TOR documentation
- 0x0.st β Null pointer file host
- OpenSSL EVP docs β AES-256-CBC API
- libcurl SOCKS5 β Proxy configuration
- NIST PBKDF2 β Key derivation standard
13. Final Thoughts
Three components, zero overlap in what they know, no single point of failure. The encryption hides the content. TOR hides the sender. 0x0.st asks no questions. None of these are new ideas β the interesting part was wiring them together in C and making sure the socks5h detail didn't get missed.
If you're reading this because you're building something similar β pay attention to your DNS. That's the part most people get wrong.
AES ate it. TOR lost it. Nobody saw nothing.