Skip to main content

Encryption

Threat model​

We protect against attackers that have access to the storage. An attacker who can read the storage backend (S3 bucket, self-hosted server, Lasco Cloud) sees only ciphertext. All blobs are encrypted before upload, and no key material is stored on the remote. Without the user's password, the attacker cannot decrypt anything.

Key derivation​

Lasco derives all keys from a single user password using Argon2id. A 32-byte random salt (salt) is generated once at library initialisation, stored on the server, and shared across all users. Its purpose is to make offline dictionary attacks against the password more expensive.

User password
│
│ Argon2id(password, salt)
▼
KEK
│
│ decrypts mk_{user}_{uuid}.enc
▼
Master Key
│
│ HKDF(MasterKey, file UUID)
▼
File Encryption Key

Each user has their own mk_{user}_{uuid}.enc containing the master key wrapped under that user's KEK. Adding a user means an existing user decrypts their master key and re-wraps it under the new user's KEK. Changing a password means re-deriving the KEK and re-wrapping the same master key under it.

Encryption per file type​

FileAlgorithmNonceNotes
mk_{username}_{uuid}.encAES-256-GCM12 bytes (random)Wraps the master key. Nonce prepended to ciphertext
.data, .thumb, .opXChaCha20-Poly130524 bytes (random)