nimir /
BioWorkContact
Get in touch

© 2026 Nimir Khan. All rights reserved.

  1. CryptoCloud
  2. Architecture
Backend Infrastructure

Architecture & Infrastructure

How CryptoCloud's backend is designed to handle encrypted file storage, secure sharing, and zero-knowledge guarantees at scale.

Tech Stack

Backend

  • FastAPI 0.104+
  • Python 3.13
  • Uvicorn (ASGI)
  • JWT Auth

Database

  • MongoDB 6.0
  • Motor (async ODM)
  • 4 Collections
  • Document Store

Storage

  • AWS S3 / DO Spaces
  • Pre-signed URLs
  • boto3 SDK
  • Direct Upload

Background

  • Celery Workers
  • Redis Broker
  • Email Tasks
  • Cleanup Jobs

System Overview

Client (Browser)
Next.js + Web Crypto API
FastAPI Backend
REST API + JWT Middleware
MongoDBMetadata + Encrypted Keys
S3 StorageEncrypted Blobs
RedisMessage Broker

MongoDB Collections

users Collection

{
  "_id": ObjectId,
  "username": "alice",                      // Plaintext
  "email": "alice@example.com",             // Plaintext
  "hashed_password": "bcrypt_hash",         // bcrypt
  "publicKey": "base64_spki",               // RSA public (plaintext)
  "encryptedPrivateKey": "base64string",    // RSA private (encrypted)
  "is_2fa_enabled": false,
  "totp_secret": null,
  "backup_codes": [],
  "quota": 5368709120,                      // 5GB in bytes
  "profile_picture_url": null
}

files Collection

{
  "_id": ObjectId,
  "filename": "document.pdf",          // Plaintext
  "owner_id": ObjectId,                // Reference to user
  "upload_time": datetime,             // UTC timestamp
  "file_path": "uploads/uid/uuid",     // S3 key
  "file_size": 1048576,                // Bytes (plaintext)
  "isFolder": false,
  "parentId": ObjectId | null,         // Folder hierarchy
  "encryptedFileKey": "base64string"   // AES key (encrypted)
}

shares Collection

{
  "_id": ObjectId,
  "owner_id": ObjectId,
  "recipient_id": ObjectId,
  "file_id": ObjectId,
  "encryptedFileKey": "base64string",  // Wrapped with RSA public key
  "shared_at": datetime
}

public_shares Collection

{
  "_id": ObjectId,
  "token": "random_32_byte_token",
  "file_id": ObjectId,
  "owner_id": ObjectId,
  "filename": "document.pdf",
  "file_size": 1048576,
  "mime_type": "application/pdf",
  "created_at": datetime,
  "expires_at": datetime,              // Auto-cleanup after 24h
  "password_hash": "bcrypt_hash" | null,
  "max_downloads": 10 | null,
  "download_count": 0,
  "is_active": true
}

File Upload Pipeline

1

Client: Generate Random File Key

Browser generates a random 256-bit AES key unique to this file.

fileKey = crypto.subtle.generateKey("AES-GCM", 256)
2

Client: Encrypt File Contents

File data encrypted with AES-256-GCM. Result includes IV, ciphertext, and authentication tag.

encryptedBlob = AES-GCM(fileKey, IV, fileData)
3

Client: Encrypt File Key

File key encrypted with user's master key (never transmitted to server).

encryptedFileKey = AES-GCM(masterKey, IV, fileKey)
4

Client → Server: Request Upload URL

POST to /files/request-upload-url with filename, size, content type.

POST /api/v1/files/request-upload-url
5

Server: Generate Pre-Signed S3 URL

Server checks quota, generates time-limited (5 min) pre-signed URL for direct S3 upload.

s3_client.generate_presigned_url("put_object", 300s)
6

Client → S3: Upload Encrypted Blob

Client uploads encrypted blob directly to S3 (bypasses backend).

PUT https://s3.amazonaws.com/bucket/uploads/...
7

Client → Server: Finalize Upload

POST to /files/finalize-upload with metadata + encrypted file key.

POST /api/v1/files/finalize-upload
8

Server: Store Metadata in MongoDB

Server creates file record with filename, size, S3 path, and encrypted file key.

db.files.insert_one(file_metadata)

File Download Pipeline

1

Client → Server: Request Download URL

GET /files/download-url/:fileId

GET /api/v1/files/download-url/65a...
2

Server: Verify Ownership & Generate URL

Server checks user owns file or has share access, generates 15-min pre-signed S3 URL.

Returns: { url: "s3_url", encryptedFileKey: "..." }
3

Client → S3: Download Encrypted Blob

Client fetches encrypted blob directly from S3.

GET https://s3.amazonaws.com/bucket/uploads/...
4

Client: Decrypt File Key

Browser decrypts file key using master key from memory.

fileKey = AES-GCM-Decrypt(masterKey, encryptedFileKey)
5

Client: Decrypt File Contents

Browser decrypts blob with file key, triggers download.

fileData = AES-GCM-Decrypt(fileKey, encryptedBlob)

Authentication Flow

Registration

  1. 1.Client derives master key: PBKDF2(password, 100k iterations)
  2. 2.Client generates RSA-4096 key pair
  3. 3.Client encrypts private key with master key
  4. 4.Server receives: username, email, password, public key, encrypted private key
  5. 5.Server hashes password with bcrypt, stores user record

Login

  1. 1.Client sends username + password to server
  2. 2.Server verifies bcrypt hash
  3. 3.If 2FA enabled: verify TOTP code
  4. 4.Server generates JWT (HS256), returns token + user data
  5. 5.Client derives master key locally, stores JWT in memory

Background Workers (Celery)

Cleanup Expired Shares

Frequency: Every 1 hour (cron)

Purpose: Delete public share links past expiration

db.public_shares.delete_many({ expires_at: { $lt: now } })

Send Email Notifications

Trigger: Async on demand

Use Cases:

  • • Login alerts (new device)
  • • 2FA setup confirmation
  • • Password reset (future)

Celery Configuration

Broker:Redis
Result Backend:Redis
Concurrency:4 workers

Deployment & Infrastructure

Containerization

  • • Docker + Docker Compose
  • • backend: FastAPI + Uvicorn
  • • celery-worker: Background tasks
  • • database: MongoDB container
  • • redis: Message broker

Production Hosting

  • • Backend: Render.com
  • • Frontend: Vercel
  • • Storage: DigitalOcean Spaces (S3)
  • • Database: MongoDB Atlas

Continue Reading

Security Model →

Threat analysis, zero-knowledge guarantees, and attack scenarios

Cryptography →

AES-GCM, RSA-OAEP, PBKDF2 implementation details