Security

Your data is encrypted on your device before it ever leaves.

We can't read it. Your sync provider can't read it. If our servers are ever breached, attackers see encrypted blobs they can't decrypt without your passphrase — which never touches our infrastructure.

MyLifePapers is a local-first, end-to-end encrypted household record manager. Your passphrase derives a key that wraps a master data key on your device. That data key — and only that data key — can decrypt your records. The data key never leaves your device unencrypted. Sync providers (Google Drive, Dropbox, OneDrive, iCloud, or our optional cloud) store encrypted blobs we can't open.

The encryption model, in one picture

Layer 1 — You
Passphrase You choose it. Never leaves your device.
↓ Argon2id, 64 MiB, 3 iterations
KEK Key Encryption Key Derived locally. Held in memory only.
unwraps ↓
Layer 2 — Your vault
DK Data Key (256-bit) Wrapped on disk; cleared on lock.
↓ XSalsa20-Poly1305 (libsodium)
Encrypted records All record data, every field, every file.
syncs as ciphertext ↓
Layer 3 — Sync provider
Opaque encrypted blob Google Drive · Dropbox · OneDrive · iCloud Drive · MyLifePapers Cloud (R2)

What we never see

  • Your passphrase. It's used to derive a key on your device, then dropped from memory. It never travels to our servers, your sync provider, or anywhere else.
  • Your data key. Stored only in memory while the app is unlocked. Wrapped on disk with your passphrase. Zeroed from memory when the app locks.
  • Your records. Names, account numbers, document files, contact details, passwords — all encrypted before they leave your device. We get opaque bytes.
  • What you're storing or how often you use the app. No analytics SDKs, no telemetry pings, no feature-usage tracking. The only data we have is what's necessary to validate your license and route encrypted sync traffic.

Where your data actually lives

On your device

The working copy: a local SQLite database, protected by your operating system's file encryption (FileVault on macOS, BitLocker on Windows, Data Protection on iOS, FBE on Android). Accessible only when the device is unlocked.

On your sync provider

An encrypted blob per household member, written to a folder you choose in your cloud storage. We never have access to your Google / Dropbox / Microsoft / iCloud account. You can revoke our access from your provider's settings at any time.

On MyLifePapers Cloud optional

For households whose members use different Google accounts (or who don't want to use a public cloud), we offer paid sync via our Cloudflare R2 bucket. Same encryption applies — we hold ciphertext we can't read. Authenticated by your license key.

How household sharing works

What happens if you forget your passphrase

If you saved your recovery code

At setup, we generate a 24-character recovery code (formatted as six 4-character groups). You're shown it once. Save it somewhere safe — paper, a password manager, a safe deposit box. With the recovery code you can unlock your vault on a new device or reset your passphrase. The recovery code is itself wrapped with the same Argon2id derivation; it works the same as a passphrase.

If you didn't

Your data is mathematically inaccessible. We cannot help. We don't have a backdoor, we don't have a master key, and we don't have a "reset" option. The same property that protects your data from us protects it from password resets. This is the trade-off of true end-to-end encryption. The fix is to save the recovery code when prompted, and back it up the way you'd back up the key to a safe.

What we protect against

  • Cloud-provider breach. If Google / Dropbox / Microsoft / iCloud / our R2 bucket is ever compromised, attackers see encrypted blobs. They cannot decrypt without your passphrase or recovery code.
  • Network attackers. All traffic is TLS-encrypted in transit. Sync requests are authenticated by license key (X-License-Key header), not cookies — closed off to CSRF.
  • Lost or stolen device. The app locks automatically after 5 minutes of inactivity, on system suspend, and on OS screen lock — even without an explicit logout. The vault is locked with full-disk-encryption quality (iOS Data Protection class Complete; equivalent on other platforms) when the device is locked.
  • Malicious apps on your phone. The mobile app uses the OS keychain (iOS) or Keystore (Android), with access groups scoped to our own signing identity. Other apps installed on your phone can't read our keys.
  • Compromised sync metadata. The folder structure on your sync provider exposes file sizes and timestamps. We don't put record names, types, or content in the filenames — they're opaque hashes.

What we honestly don't protect against

  • Malware on a device you're actively using. If your laptop is keylogged, no encryption product can help — we're decrypting your records for you in memory by design.
  • A weak passphrase combined with a leaked vault blob. Our Argon2id parameters make brute force expensive (about 0.5 seconds per attempt on modern hardware), but a 6-character common password is still attackable. Use a passphrase, not a password. Three random words beats one clever word.
  • A household member you've shared with going rogue. If you've shared a record with someone, they have a decryption-capable copy. Removing them from the household stops new shares from reaching them, but you can't reach back into their device.
  • Hostile state-actor attacks. If a nation-state targets you specifically with on-device exploits, our threat model doesn't cover you. Use a hardware key, an air-gapped device, or both.

Technical details

For the security-curious or anyone vetting us for an integration.

Encryption primitive
libsodium crypto_secretbox_easy (XSalsa20-Poly1305), authenticated encryption with associated data.
Key derivation
Argon2id, memory = 64 MiB, time = 3, parallelism = 1, 16-byte salt. These parameters are OWASP's recommended profile for "sensitive" applications.
Data key (DK)
256-bit symmetric key, generated via libsodium crypto_secretbox_keygen. Random for each new household. Wrapped per-member with each member's passphrase-derived KEK.
Member sharing
crypto_box_seal (X25519 + XSalsa20-Poly1305 + BLAKE2b) to a member's public key. New members never need the admin's passphrase — only their own.
Vault envelope
Versioned wire format (currently mlp-vault-v6). Backwards-compatible by design — older versions remain readable forever; format bumps are paired with read paths that handle both.
At-rest on device
iOS: Keychain with kSecAttrAccessibleWhenUnlockedThisDeviceOnly, app-group restricted to our signing team ID. Android: Keystore-backed, with backups disabled (allowBackup="false" + per-domain data-extraction-rules excluded). macOS/Windows: full-disk encryption is the user's responsibility; we hold the data key in process memory only while unlocked.
Auto-lock
5-minute idle timeout, lock on system suspend, lock on OS screen lock. The data key is zeroed from memory on lock.
Trusted Access & Send
When you share a record outside the household, we encrypt it with a separate access code (PBKDF2-SHA256 → AES-256-GCM via WebCrypto). The access code is never sent to us — it lives in the link you share. Without it, the blob is unreadable to us and to anyone who intercepts the link.
Random sources
libsodium's randombytes_buf on native code paths; crypto.getRandomValues (WebCrypto CSPRNG) in the renderer; crypto.randomBytes (Node CSPRNG) in the desktop main process. We don't use Math.random anywhere a key, nonce, or token is generated.
On-device AI
Document classification and embedding for search run entirely on your device. Records are never sent to a third-party AI provider. Optional summarization uses Apple Foundation Models (iOS 26+), Gemini Nano (Android), or Phi Silica (Windows) — all on-device.

Found something?

We take security reports seriously. Email security@mylifepapers.com with reproduction steps. We aim to respond within 48 hours and coordinate disclosure responsibly.

We don't have a formal bug bounty yet. Researchers who report verified security issues get attribution (if they want it) and our thanks.