Back to Home

Security Model

Security isn't an afterthought — it's the foundation everything is built on. Here's exactly how LastSignal protects your most sensitive messages.

Zero-Knowledge Architecture

"Zero-knowledge" means the server stores your data but cannot understand it. Even if the database was completely exposed, your messages would remain private.

What the Server Stores

  • Your email address
  • Encrypted message blobs (unreadable)
  • Recipient public keys
  • Message labels (optional metadata)
  • Timestamps and check-in status

What the Server Cannot Access

  • Your message contents
  • Recipient passphrases
  • Recipient private keys
  • Decryption keys
  • Any way to read your messages

Encryption Flow

Three key processes work together to keep your messages secure. All cryptographic operations happen in your browser — the server never sees plaintext or private keys.

1. Recipient Key Setup

When a recipient accepts your invitation, they create a passphrase. This passphrase generates a unique encryption key pair that only they can recreate.

┌────────────────────────────────────────────────────────────┐
│                   RECIPIENT KEY SETUP                      │
│       How recipients create their encryption keys          │
├────────────────────────────────────────────────────────────┤
│                                                            │
│    ┌─────────────┐                                         │
│    │ Passphrase  │  (chosen by recipient, never sent)      │
│    └──────┬──────┘                                         │
│           │                                                │
│           ▼                                                │
│    ┌─────────────┐     ┌──────────────┐                    │
│    │  Argon2id   │◄────│ Random Salt  │                    │
│    │   256 MB    │     │  (16 bytes)  │                    │
│    └──────┬──────┘     └──────────────┘                    │
│           │                                                │
│           ▼                                                │
│    ┌─────────────┐                                         │
│    │    Seed     │  (32 bytes, deterministic)              │
│    └──────┬──────┘                                         │
│           │                                                │
│           ▼                                                │
│    ┌─────────────┐                                         │
│    │   X25519    │                                         │
│    │   Keypair   │                                         │
│    └──────┬──────┘                                         │
│           │                                                │
│     ┌─────┴─────┐                                          │
│     ▼           ▼                                          │
│ ┌────────┐  ┌─────────┐                                    │
│ │ Public │  │ Private │                                    │
│ │  Key   │  │   Key   │                                    │
│ └───┬────┘  └────┬────┘                                    │
│     │            │                                         │
│     ▼            ▼                                         │
│  Stored      Discarded                                     │
│  on server   immediately                                   │
│                                                            │
└────────────────────────────────────────────────────────────┘

Key insight: The private key is generated from the passphrase, used once, and immediately discarded. It can be regenerated anytime using the same passphrase and salt.

2. Message Encryption

When you write a message, it's encrypted in your browser using a random key. That key is then encrypted separately for each recipient using their public key.

┌────────────────────────────────────────────────────────────┐
│                    MESSAGE ENCRYPTION                      │
│            How your messages are protected                 │
├────────────────────────────────────────────────────────────┤
│                                                            │
│    ┌─────────────┐                                         │
│    │  Plaintext  │  (your message, in browser only)        │
│    │   Message   │                                         │
│    └──────┬──────┘                                         │
│           │                                                │
│           ▼                                                │
│    ┌─────────────────────┐     ┌──────────────┐            │
│    │ XChaCha20-Poly1305  │◄────│ Random Key   │            │
│    │       (AEAD)        │     │  (32 bytes)  │───────┐    │
│    └──────────┬──────────┘     └──────────────┘       │    │
│               │                                       │    │
│               ▼                                       │    │
│    ┌─────────────────────┐                            │    │
│    │     Ciphertext      │                            │    │
│    │  (encrypted blob)   │                            │    │
│    └──────────┬──────────┘                            │    │
│               │                                       │    │
│               │         For each recipient:           │    │
│               │         ┌──────────────────┐          │    │
│               │         │  crypto_box_seal │◄─────────┘    │
│               │         │   (sealed box)   │               │
│               │         └────────┬─────────┘               │
│               │                  │                         │
│               │                  ▼                         │
│               │         ┌──────────────────┐               │
│               │         │   Wrapped Key    │               │
│               │         │ (per recipient)  │               │
│               │         └────────┬─────────┘               │
│               │                  │                         │
│               ▼                  ▼                         │
│    ┌─────────────────────────────────────────┐             │
│    │            Sent to Server               │             │
│    │  • Ciphertext (encrypted message)       │             │
│    │  • Wrapped keys (one per recipient)     │             │
│    │  • Nonce (random, for decryption)       │             │
│    └─────────────────────────────────────────┘             │
│                                                            │
└────────────────────────────────────────────────────────────┘

Key insight: The message is encrypted once with a symmetric key. Only the small key (not the whole message) is encrypted per-recipient, making the system efficient even with many recipients.

3. Message Decryption

When a recipient receives a message, they enter their passphrase to regenerate their key pair and decrypt the message — all in their browser.

┌────────────────────────────────────────────────────────────┐
│                    MESSAGE DECRYPTION                      │
│           How recipients read your messages                │
├────────────────────────────────────────────────────────────┤
│                                                            │
│    ┌─────────────┐     ┌─────────────┐                     │
│    │ Passphrase  │     │    Salt     │  (from server)      │
│    └──────┬──────┘     └──────┬──────┘                     │
│           │                   │                            │
│           └─────────┬─────────┘                            │
│                     ▼                                      │
│              ┌─────────────┐                               │
│              │  Argon2id   │  (same params as setup)       │
│              └──────┬──────┘                               │
│                     │                                      │
│                     ▼                                      │
│              ┌─────────────┐                               │
│              │   Keypair   │  (regenerated identically)    │
│              └──────┬──────┘                               │
│                     │                                      │
│    ┌────────────────┼────────────────┐                     │
│    │                ▼                │                     │
│    │  ┌─────────────────────────┐    │                     │
│    │  │  crypto_box_seal_open   │◄───┼─── Wrapped Key      │
│    │  └───────────┬─────────────┘    │    (from server)    │
│    │              │                  │                     │
│    │              ▼                  │                     │
│    │  ┌─────────────────────────┐    │                     │
│    │  │      Message Key        │    │                     │
│    │  └───────────┬─────────────┘    │                     │
│    │              │                  │                     │
│    │              ▼                  │                     │
│    │  ┌─────────────────────────┐    │                     │
│    │  │  XChaCha20-Poly1305     │◄───┼─── Ciphertext       │
│    │  │       Decrypt           │    │    (from server)    │
│    │  └───────────┬─────────────┘    │                     │
│    │              │                  │                     │
│    │              ▼                  │                     │
│    │  ┌─────────────────────────┐    │   All in browser    │
│    │  │       Plaintext         │    │   Never sent back   │
│    │  │        Message          │    │                     │
│    │  └─────────────────────────┘    │                     │
│    └─────────────────────────────────┘                     │
│                                                            │
└────────────────────────────────────────────────────────────┘

Key insight: The decrypted message is displayed in the browser and never sent back to the server. The server has no way to know what the message says.

Cryptographic Algorithms

Purpose Algorithm Parameters Library
Key Derivation Argon2id 256 MB memory, 3 iterations libsodium
Message Encryption XChaCha20-Poly1305 256-bit key, 192-bit nonce libsodium
Key Wrapping X25519 + crypto_box_seal Curve25519 libsodium
Token Hashing SHA-256 Standard Ruby OpenSSL

Why These Choices?

Argon2id

Winner of the Password Hashing Competition. Memory-hard design resists GPU and ASIC attacks, making brute-force extremely expensive.

XChaCha20-Poly1305

Modern AEAD cipher. Extended nonce eliminates collision risks. Faster than AES on devices without hardware acceleration.

X25519

Industry-standard elliptic curve. Used by Signal, WhatsApp, and TLS 1.3. Fast, secure, and well-audited.

libsodium

Widely audited cryptographic library with misuse-resistant API. No configuration needed — secure by default.

Threat Model

LastSignal is designed to protect against the most likely attack scenarios. Here's what happens in each case:

🖥️ Server Compromise

Scenario: An attacker gains full access to the database.

They get:

  • • Encrypted message blobs
  • • Recipient public keys
  • • Email addresses
  • • Argon2id salts

They can't get:

  • • Message contents
  • • Passphrases or private keys
  • • Any way to decrypt messages

Protection: End-to-end encryption means a database breach doesn't expose your messages.

🔗 Man-in-the-Middle

Scenario: An attacker intercepts traffic between you and the server.

  • • TLS/HTTPS enforced in production
  • • HSTS prevents downgrade attacks
  • • All crypto happens client-side before transmission

Residual risk: Compromised Certificate Authorities (rare, detectable).

🔨 Brute Force Attacks

Scenario: An attacker tries to guess recipient passphrases.

  • • Argon2id requires 256 MB memory per attempt
  • • Rate limiting on all endpoints
  • • No server feedback on wrong passphrase
  • • Offline attacks require both ciphertext and salt

Important: Weak passphrases are still vulnerable. Use 16+ random characters.

👤 Malicious Server Operator

Scenario: The person running the server tries to read your messages.

  • • Server only receives encrypted data
  • • No access to passphrases (never transmitted)
  • • Cannot derive private keys from public keys
  • • Open source code allows verification

Protection: Zero-knowledge architecture means even the operator can't read messages.

📧 Compromised Email Account

Scenario: An attacker gains access to a user's email.

They can:

  • • Intercept magic login links
  • • Access the sender's account
  • • Trigger or cancel message delivery

They can't:

  • • Read encrypted messages
  • • Obtain recipient passphrases
  • • Decrypt messages without passphrase

Mitigation: Use a secure email provider and enable 2FA on your email account.

🌐 Malicious JavaScript Injection

Scenario: An attacker compromises the server to serve malicious JavaScript.

  • • Could capture passphrases as users type them
  • • Could exfiltrate decrypted messages
  • • This is the main trust boundary for any web-based E2E encryption

Mitigation: Self-host your own instance. Audit the code. Use browser extensions to verify script integrity.

🧩 Compromised Browser or Extensions

Scenario: A malicious browser extension or compromised device alters what the client sees or captures keystrokes.

  • • Could read passphrases as you type them
  • • Could capture decrypted messages before display
  • • Could tamper with the UI to mislead users

Mitigation: Use a trusted device, minimize extensions, and consider a dedicated browser profile for LastSignal.

💻 Physical Device Access

Scenario: An attacker has physical access to a recipient's device.

  • • If passphrase is saved in browser/password manager, messages can be read
  • • Browser history may reveal the decryption URL
  • • Decrypted messages may be in browser memory or cache

Mitigation: Use full-disk encryption. Lock your device. Don't save passphrases in browsers on shared computers.

⚖️ Legal Compulsion

Scenario: A government demands access to user data.

  • • Server can provide encrypted blobs, emails, and metadata
  • • Server cannot provide message contents (doesn't have them)
  • • Server cannot provide passphrases (never stored)
  • • Mathematical impossibility, not policy choice

Protection: Zero-knowledge design means compliance with data requests doesn't compromise message privacy.

Known Limitations

Honest security communication matters. Here's what LastSignal doesn't protect:

Metadata Exposure

The server knows who sends messages to whom, and when. This is necessary for the service to function.

Message Labels

Labels are stored in plaintext. Avoid putting sensitive information in labels.

Trust in Client Code

You must trust the JavaScript the server delivers. The code is open source, but you're trusting your browser to run it correctly.

No Forward Secrecy

If a passphrase is compromised, all past messages to that recipient are exposed. There's no way to rotate keys for existing messages.

Verify It Yourself

LastSignal is fully open source. Read the code, audit the crypto, or deploy your own instance. Don't take anyone's word for it — verify.

LastSignal is provided as-is, without warranties or guarantees. We do not host or operate your instance, and bugs may exist. You are solely responsible for how you configure, run, and use it. See the full disclaimer.