Skip to content

Per-user client-side file encryption with envelope-encrypted DEKs #6

@devangb3

Description

@devangb3

IPFS is public anyone who accidently gets the CID can retrieve the bytes. End-to-end encryption fixes this

Current state:
Files are uploaded to IPFS in plaintext.

Proposed implementation:

  1. On signup: generate an X25519 key pair client-side. Encrypt the private key with a key derived from the password (PBKDF2 or Argon2id → AES-256-GCM). Store ciphertext + salt server-side under a fourth KV key "<user> IDENTITY".
  2. On login: server returns the encrypted identity. Frontend decrypts it in memory with the password. Drop password from memory.
  3. On upload: generate a random 256-bit DEK, encrypt the file with AES-256-GCM, push ciphertext to IPFS. Encrypt the DEK with the user's public key (sealed box via libsodium). Store wrapped DEK + nonce + tag in the node's file_obj.
  4. On share: fetch recipient's public key, re-wrap the DEK with the recipient's public key, put the new wrapped DEK into the shared Node copy.
  5. Use libsodium.js / tweetnacl on the frontend, PyNaCl on the backend (only for recipient public-key lookup, not for private keys).

Files likely affected:

  • frontend/src/utils/crypto.js (new)
  • frontend/src/utils/api.js (upload/download flow changes)
  • backend/user_authentication_service.py (store encrypted identity)
  • backend/node.py / backend/file.py (carry wrapped DEK)
  • app.py

Acceptance criteria:

  • A file uploaded by user A cannot be read by visiting the IPFS gateway directly.
  • A file shared from A to B is decryptable by B and only B.
  • Server operators (even with full DB access) cannot decrypt any file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions