Encrypted-only file storage.
For high-stakes enterprise storage, journalists, and activists. Darkdot Files accepts PGP-encrypted uploads and stores them by ciphertext hash. We never see your plaintext or filenames.
How it works
- Anonymous by default
- A random 16-character account number and a password are your identity. No email or name required. Add a PGP key later for two-factor sign-in.
- Encrypted uploads only
- Every object must be OpenPGP ciphertext. The server inspects the packet structure without decrypting and refuses plaintext before it is stored.
- Content-addressed
- Objects are named by the SHA-256 of their ciphertext. Identical uploads deduplicate to the same object.
- HTTP and S3
- A Bearer-token HTTP API, plus an S3 SigV4 subset for
rclone. - Pay with privacy
- Top up a credit balance with Monero (XMR); usage deducts from it.
- Tor
- The console is also an onion service: http://k5git7r4pyskwl7qt6iobl4cvattn7tdhrpzmzl3ubkyuwpzbkbeanqd.onion
Quick Start
-
Create an account and save your account number
Create an account with a password. You get a 16-character account number - the only identifier we issue. Store it like a password; it can't be recovered.
-
Generate a PGP keypair
All uploads must be encrypted to a key you control. We never see your private key.
gpg --full-generate-key gpg --armor --export your@email > pubkey.asc
-
Create a bucket and an access key
In the console, create a bucket on the R2 or S3 backend, then mint an access key. The
sk_…secret is shown once; theDDF…key id names the key. The bucket's backend selects its data endpoint.export DDF_ENDPOINT=https://r2.files.darkdot.com # R2 buckets # export DDF_ENDPOINT=https://s3.files.darkdot.com # S3 buckets export DDF_BUCKET=<your-bucket-name> export DDF_SECRET=sk_…
-
Encrypt and upload
POST the encrypted file to the bucket. The server hashes the ciphertext and returns the canonical URL in the
Locationheader - you never compute SHA-256 yourself. The console shows each backend's maximum object size.curlgpg --encrypt --recipient your@email file.pdf curl -X POST \ -H "Authorization: Bearer $DDF_SECRET" \ --data-binary @file.pdf.gpg \ "$DDF_ENDPOINT/$DDF_BUCKET" # → 201 Created # Location: $DDF_ENDPOINT/$DDF_BUCKET/3a7bd2f9c8e1...d4f0
pythonimport os, requests with open('file.pdf.gpg', 'rb') as f: r = requests.post( os.environ['DDF_ENDPOINT'] + '/' + os.environ['DDF_BUCKET'], headers={'Authorization': 'Bearer ' + os.environ['DDF_SECRET']}, data=f, ) print(r.headers['Location']) # canonical URLrclone# ~/.config/rclone/rclone.conf [darkdot] type = s3 provider = Other # endpoint for S3 buckets: https://s3.files.darkdot.com endpoint = https://r2.files.darkdot.com access_key_id = DDF… secret_access_key = sk_… # multipart upload is unsupported; this forces a single-part PUT rclone --s3-upload-cutoff 5G copy file.pdf.gpg darkdot:<your-bucket-name>/
-
Download and decrypt
curl -H "Authorization: Bearer $DDF_SECRET" \ -o file.pdf.gpg "$DDF_ENDPOINT/$DDF_BUCKET/<sha256>" gpg --decrypt file.pdf.gpg > file.pdf