Encryption Details
Technical details about Docket's encryption implementation.
Cryptographic Standards
Password to Key: Argon2id
Your password is converted to an encryption key using Argon2id:
| Parameter | Value |
|---|---|
| Algorithm | Argon2id |
| Memory | 64 MiB |
| Iterations | 3 |
| Parallelism | 4 |
| Output | 256 bits |
| Salt | 128 bits (random, per-vault) |
Why Argon2id?
- Memory-hard: Resistant to GPU/ASIC attacks
- Winner of the Password Hashing Competition
- OWASP recommended
Database: SQLCipher
All structured data is stored in an encrypted SQLite database:
| Parameter | Value |
|---|---|
| Algorithm | AES-256-CBC |
| Page Size | 4096 bytes |
| KDF | PBKDF2-HMAC-SHA512 |
| HMAC | SHA512 per-page |
Files: AES-256-GCM
Individual files are encrypted with authenticated encryption:
| Parameter | Value |
|---|---|
| Algorithm | AES-256-GCM |
| Key | 256 bits (random, per-file) |
| Nonce | 96 bits (random) |
| Auth Tag | 128 bits |
File format:
[nonce: 12 bytes][ciphertext][auth_tag: 16 bytes]
Two-Layer Key System
┌─────────────────┐
│ Your Password │
└────────┬────────┘
│ Argon2id + salt
▼
┌─────────────────┐
│ Derived Key │──────► Encrypts Database
│ (256 bits) │ (chats, metadata, file keys)
└─────────────────┘
│
│ Per-file keys
▼
┌─────────────────┐
│ Random File Keys│──────► Encrypted Files
│ (256 bits each) │
└─────────────────┘
Benefits:
- Password change only re-keys database, not all files
- Each file has independent key (compromise isolation)
- File keys are random (not derived from password)
Metadata Hiding
Files on disk reveal nothing about their contents:
On-disk filename:
f_a1b2c3d4e5f67890.enc
In encrypted database:
id: "abc123"
disk_filename: "f_a1b2c3d4e5f67890.enc"
original_name: "my-vacation-photo.jpg"
mime_type: "image/jpeg"
size: 2456789
encryption_key: [256-bit random key]
Benefits:
- Original filename never visible on disk
- File type not inferable from extension
- Prevents targeted attacks based on filenames
Mode Switching
Enabling Encryption
- Enter new password
- Salt generated, key derived
- Database converted to SQLCipher
- Each file encrypted with random key
- Files renamed to random format
Disabling Encryption
- Verify current password
- Database converted to plain SQLite
- Each file decrypted
- Files renamed to original names
- Salt removed
Both operations are crash-safe with atomic writes.
Memory Security
Key Handling
- Derived key kept in memory while unlocked
- Key immediately zeroed on lock (using
zeroize) - No key material written to disk
USB Disconnect
When the USB is disconnected:
- Drive disconnect detected (within 2 seconds)
force_lock_vault()called- Key zeroed from memory
- All sessions invalidated
- UI cleared of decrypted content
Browser Security
On lock:
- All blob URLs revoked
- React state cleared
- WebView reloaded (clears all memory)
- localStorage/sessionStorage cleared
Threat Model
Protected Against
| Threat | Mitigation |
|---|---|
| USB drive theft | All data encrypted at rest |
| Filesystem browsing | No plaintext secrets or files |
| Filename leakage | Random disk filenames |
| Weak password attacks | Argon2id with 64MB memory cost |
| File tampering | AES-GCM authentication |
| Cold boot attack | Keys zeroed on lock |
Not Protected Against
| Threat | Reason |
|---|---|
| Malware on host PC | App runs with user privileges |
| Memory dump while unlocked | Key must be in memory to decrypt |
| Keylogger | Outside app's control |
Recommendations
- Use a strong password — Long, unique, not used elsewhere
- Lock when not in use — Click lock or remove the USB
- Use encrypted mode — Unless you have a specific reason not to
- Be careful on untrusted computers — Malware could capture your password