End-to-End Encryption Architecture
zeitkapsl uses end-to-end encryption (E2EE) to ensure your photos remain private and secure. This page explains how the encryption architecture works to protect your data.
Core Concept
With zeitkapsl's E2EE architecture, your photos are "locked before they leave your device." Think of it like a photo album with a padlock:
- Only you and authorized recipients have the key to unlock it
- The zeitkapsl servers only store the locked album
- No one else, not even zeitkapsl, can see your photos
What is End-to-End Encryption?
End-to-end encryption means that your data is encrypted on your device before being sent to the server, and can only be decrypted by you or people you explicitly share with. The encryption keys never leave your control.
Encryption and keys
The Key Hierarchy
zeitkapsl uses separate keys for login, account recovery, collections, and media:
Email + password → PBKDF2 + HKDF → encryption key + auth token
Random main key → index key → collection key → media keyThe password-derived encryption key wraps the random main key. Each photo or video has its own AES-256-GCM key, and collection keys allow collection sharing without exposing the main key.
Encryption in Action
Every photo and video is encrypted with:
- Algorithm: AES-256-GCM (a strong, standard authenticated cipher)
- Unique Key: Each media item gets its own random 256-bit key
- Authenticated Encryption: GCM mode ensures data integrity and authenticity
- Metadata Protection: Filenames, EXIF data, GPS coordinates, dates, all encrypted
Registration and Key Generation
When you create a zeitkapsl account:
Password Entry: You provide your master password (never sent to servers in plain text)
Key Derivation: PBKDF2-SHA512 and HKDF-SHA512 derive an encryption key and an authentication token from your email address and password.
Main Key: Your device generates a random main key. An index key derived from it protects collection keys and search indexes.
Wrapped Main Key: The random main key is encrypted with the password-derived encryption key and stored on the server
- This allows you to log in from multiple devices
- The server cannot decrypt this wrapped key without your password
Recovery Kit: A backup of your main key is provided
- Enables password recovery without server access
- Critical: Store this safely, because losing it means losing access if you forget your password
Important
zeitkapsl cannot recover your password or decrypt your data. If you lose both your password and recovery kit, your data is unrecoverable. This is a feature, not a bug. It is what makes the encryption genuinely end-to-end.
Sharing Architecture
zeitkapsl's sharing system is designed to share access without compromising security.
Share Link Structure
When you share a collection, zeitkapsl generates a link like:
https://app.zeitkapsl.eu/s/123456789/#abcdefThis link has two parts:
- Public Part (
/s/123456789): Identifies which share on the server - Private Part (
#abcdef): Contains the secret password, never sent to servers
URL Fragments and Privacy
Per RFC 3986, the fragment (everything after #) is never transmitted to servers. Browsers keep it local, ensuring zeitkapsl servers never see your share passwords.
Sharing step by step
You Create a Share:
- Your device generates a random share password client-side
- The share password encrypts the album key
- The encrypted album key is sent to the server
- The share password is put in the URL fragment (
#abcdef)
You Send the Link:
- The complete link (including
#abcdef) is copied to your clipboard - You send it to recipients via your preferred method (email, messaging, etc.)
- The complete link (including
Recipient Opens the Link:
- Their browser loads the page with the share ID (
123456789) - JavaScript extracts the share password from the URL fragment (
#abcdef) - The share password goes through PBKDF2 → HKDF to derive decryption keys
- The device requests the encrypted album key from the server
- The device decrypts the album key with the derived key
- The device uses the album key to decrypt photo keys
- Photos are downloaded and decrypted entirely client-side
- Their browser loads the page with the share ID (
What the Server Sees:
- A request for share ID
123456789 - Encrypted album key
- Encrypted photos being downloaded
- Never sees the share password or decrypted content
- A request for share ID
Collaborative Sharing
For collaborative albums where recipients can upload:
- Recipients receive the album key via the share link
- They can encrypt new photos with that album key
- The server links uploaded media to the shared collection
- All participants see the same encrypted collection
Password Recovery
zeitkapsl supports password recovery while maintaining E2EE:
With Recovery Kit
- You initiate password reset
- You provide your recovery kit (contains your encrypted main key)
- Your device decrypts the main key locally
- You set a new password
- The main key is re-encrypted with the new password
- The new wrapped main key is sent to the server
No Server Access
The server never sees your main key or new password in plaintext. All decryption and re-encryption happens on your device.
Without Recovery Kit
If you lose both your password and recovery kit:
- Your data cannot be recovered
- This is by design, no backdoors exist
- Create a new account and start fresh
Critical: Save Your Recovery Kit
Download and securely store your recovery kit immediately after account creation. Consider:
- Printing it and storing in a safe place
- Saving to a password manager
- Storing in multiple secure locations
What Is Encrypted
zeitkapsl encrypts everything sensitive end-to-end:
| Data Type | Encrypted | Notes |
|---|---|---|
| Photos & Videos | ✅ Yes | Each file encrypted with unique AES-256-GCM key |
| Thumbnails | ✅ Yes | Multiple sizes, all encrypted |
| Filenames | ✅ Yes | Original names encrypted |
| EXIF Metadata | ✅ Yes | Camera info, settings encrypted |
| GPS Coordinates | ✅ Yes | Location data fully encrypted |
| Dates & Times | ⚠️ taken time visible for quota/sorting | |
| Collection Names | ✅ Yes | Album names encrypted |
| Collection Descriptions | ✅ Yes | Any descriptions encrypted |
| Search Indexes | ✅ Yes | Face data, object labels, OCR text, all encrypted |
| Folder Structure | ✅ Yes | Part of encrypted collection names |
| Share Passwords | ✅ Yes | Never leave your device; stored in URL fragments |
What Is NOT Encrypted
Some metadata is intentionally not encrypted for functionality and performance:
| Data Type | Encrypted | Why Not Encrypted |
|---|---|---|
| Upload Size | ❌ No | Required for quota tracking |
| Upload Timestamp | ❌ No | Enables fast timeline sorting without decryption |
| Aspect Ratio | ❌ No | Allows efficient grid layout without decrypting |
| Account Email | ❌ No | Required for login and communication |
| Billing Information | ❌ No | Required for payment processing |
| Collection Item Count | ❌ No | Enables fast collection list rendering |
| Collection Relationships | ❌ No | Who owns what collection |
Design Trade-offs
These choices balance privacy with usability. For example, encrypting aspect ratios would require decrypting every photo just to render the gallery grid, making the app unusably slow.
Technical Implementation
Cryptographic Primitives
zeitkapsl uses industry-standard, well-audited cryptographic libraries:
- AES-256-GCM: Symmetric encryption for data
- PBKDF2-SHA512: Password-based key derivation
- HKDF-SHA512: Key derivation for sub-keys
- BCRYPT: Server-side auth token hashing
Key Sizes
- AES Keys: 256 bits
- Derived Keys: 256 bits
Key derivation
A diagram and ASCII reference show the key hierarchy.
Registration, step by step
sha512(email)is used as the salt and yourpasswordas the key material for PBKDF2, producing thepasswordKey.- From
passwordKey, HKDF derives anencryptionKeyand anauthToken. - A
mainKeyis generated from a secure random source. This is the key your recovery kit backs up. - From
mainKey, HKDF derives anindexKeyand apasswordResetToken.indexKeydecrypts yourcollectionKeyitems, which decryptmediaKeyitems, which decrypt the actual media blobs and metadata.- From
indexKey, HKDF derives thesearchLabelsKeyused for encrypted search. passwordResetTokenproves ownership of themainKeyand enables password reset.
- The
mainKeyis wrapped with theencryptionKeyusing AES-GCM, givingwrappedMainKey. - The
authTokenis sent to the server and stored hashed with bcrypt. It is effectively your API password. - The server stores
wrappedMainKey, youremail, and thepasswordResetToken.
Key hierarchy:
email + password → PBKDF2 → HKDF → authToken + encryptionKey
mainKey → indexKey + passwordResetToken → collectionKey → mediaKeyLogin
- You enter
emailandpassword. - PBKDF2 produces the
passwordKey, and HKDF derives theencryptionKeyandauthTokenagain. - The client authenticates with
authTokenand fetcheswrappedMainKey. - The client unwraps it with
encryptionKeyvia AES-GCM to recover themainKey.
Because these keys are recomputed on your device every time, nothing that can decrypt your library is ever stored on our servers.
Recipient decryption flow for a share
The secret in a share link (https://app.zeitkapsl.eu/s/123456789/#abcdef) is the part after the #. Per RFC 3986, Section 3.5, the fragment is never sent to the server, so we can deliver the encrypted data without ever learning the key that opens it.
Share password (from #fragment)
↓ PBKDF2
Share key
↓ HKDF
authKey (bcrypt) + indexKey (AES-256-GCM)
↓
Collection key
↓
Media keys
↓
Files decrypted locallyRecipients decrypt a share with the secret in its URL fragment. zeitkapsl does not receive that fragment.
Open Source Transparency
zeitkapsl is open source (GPLv3 licensed):
- All client-side encryption code is auditable
- Security researchers can review the implementation
- Community contributions improve security
- No security through obscurity
View the source code on Codeberg: codeberg.org/zeitkapsl/zeitkapsl. The cryptography lives in core/pkg/crypto.
And you do not have to read the code yourself to gain confidence: this design was checked by an independent security audit. See independent security audit.