← Back

Security

A technical deep-dive into how PrivyPad protects your data.

Overview

PrivyPad is built on a zero-knowledge architecture. All note content is encrypted and decrypted entirely on your device. The server only ever stores encrypted blobs — it never receives your plaintext notes or your encryption key. Even if the server were compromised, your notes would remain unreadable.

This page explains the cryptographic primitives and design decisions behind PrivyPad for those who want to verify the security model.

Encryption: AES-256-GCM

Every note (title and content) is encrypted using AES-256-GCM (Advanced Encryption Standard with 256-bit keys in Galois/Counter Mode). This is the same encryption standard used by governments, banks, and security-critical applications worldwide.

How it works

  • A 256-bit key is used to encrypt your data. The key space is 2256 — brute-forcing this is computationally infeasible with any known or foreseeable technology.
  • GCM (Galois/Counter Mode) provides authenticated encryption: it ensures both confidentiality (no one can read your data) and integrity (no one can tamper with it without detection).
  • Each encryption operation uses a unique 12-byte IV (initialization vector) generated via crypto.getRandomValues(). This ensures that encrypting the same plaintext twice produces different ciphertext.
  • The IV is stored alongside the ciphertext (it is not secret) and is required for decryption.

Key Derivation: Argon2id

Your encryption key is not your password — it is derived from your password using Argon2id, the winner of the Password Hashing Competition (2015) and the recommended algorithm by OWASP for password-based key derivation.

Why Argon2id

  • Memory-hard: Unlike PBKDF2 or bcrypt, Argon2id requires a configurable amount of memory to compute. This makes it resistant to GPU and ASIC-based cracking attacks, which have limited memory per core.
  • Hybrid mode (id): Argon2id combines Argon2i (side-channel resistant) and Argon2d (GPU resistant) in a single pass, providing the best of both worlds.
  • Per-user salt: Each user has a unique, randomly generated 16-byte salt stored on the server. This prevents rainbow table attacks and ensures two users with the same password produce different keys.

Parameters

Memory cost65536 KiB (64 MB)Time cost (iterations)3Parallelism1Output length32 bytes (256 bits)Salt length16 bytes

The derived 256-bit key is imported into the Web Crypto API as a non-extractable CryptoKey object. It exists only in browser memory and is never written to disk, cookies, localStorage, or transmitted to the server.

Key Verification

When you register, PrivyPad encrypts a known sentinel string (“PRIVYPAD_KEY_CHECK”) with your derived key and stores the result as your encryption key verifier. On subsequent logins and unlock attempts, the app re-derives the key, attempts to decrypt the verifier, and checks that the result matches the sentinel. If decryption fails or the plaintext doesn't match, the password is wrong.

This approach avoids ever sending your password or key to the server for verification. The entire check happens client-side.

Web Crypto API

All cryptographic operations (AES-GCM encrypt/decrypt, key import, random IV generation) are performed using the browser's built-in Web Crypto API (window.crypto.subtle). This API:

  • Is implemented natively by the browser in C/C++ — not in JavaScript — making it significantly faster and more secure than any JS crypto library.
  • Supports non-extractable keys: once the AES key is imported, JavaScript code cannot read the raw key bytes back. The key can only be used for encrypt/decrypt operations.
  • Uses the operating system's CSPRNG (cryptographically secure pseudo-random number generator) for IV generation via crypto.getRandomValues().

Zero-Knowledge Architecture

“Zero-knowledge” means PrivyPad's servers have zero knowledge of your plaintext data. Here is exactly what the server stores and what it never sees:

Server stores

  • Your email address (for login)
  • Supabase-managed password hash
  • Your encryption salt (random, not secret)
  • Encrypted key verifier blob
  • Encrypted note title + IV
  • Encrypted note content + IV
  • Note metadata (timestamps, pinned, trashed)

Server never sees

  • Your plaintext password
  • Your encryption key
  • Your plaintext note titles
  • Your plaintext note content
  • Any decrypted data of any kind

End-to-End Encryption Flow

Here's the complete lifecycle of a note from creation to retrieval:

Writing a note

  1. You type in the editor. The plaintext exists only in browser memory.
  2. On save, the title and content are each encrypted with AES-256-GCM using your in-memory key, each with a fresh random IV.
  3. The encrypted ciphertext + IV pairs are sent to the server and stored.

Reading a note

  1. The server returns the encrypted ciphertext + IV pairs.
  2. Your browser decrypts the title and content using the in-memory key.
  3. The plaintext is rendered in the editor. It never touches the network unencrypted.

Page refresh / session resume

  1. The encryption key is lost (it was only in memory).
  2. PrivyPad shows an unlock modal asking for your password.
  3. Your key is re-derived from your password + salt, verified against the key verifier, and notes become readable again.

Local Mode

PrivyPad offers a fully local mode that requires no account and makes no network requests. In local mode:

  • An AES-256-GCM key is generated via crypto.subtle.generateKey() and stored in IndexedDB.
  • Notes are stored as plaintext in IndexedDB (since the key is already on-device, encrypting locally-stored data with a locally-stored key provides no additional security).
  • No data is ever sent to a server. Clearing your browser data permanently deletes everything.

Secured Notes (Sharing)

Secured notes allow you to create encrypted, shareable notes with additional protections:

  • Content is encrypted client-side with AES-256-GCM before being sent to the server.
  • A unique share link includes the decryption key in the URL fragment (after the #), which is never sent to the server by browsers.
  • Optional burn after read: the note is permanently deleted from the server after being viewed once.
  • Optional expiration: notes are automatically deleted after a configurable time period.

Collaborative Notes

PrivyPad supports real-time collaboration on shared notes while maintaining end-to-end encryption. Multiple users can edit the same note simultaneously, and all changes are encrypted before leaving the browser.

How sharing works

  • Each shared note has its own per-note AES-256-GCM key, separate from your personal encryption key.
  • When you invite a collaborator, the note key is wrapped (encrypted) with their personal key — only they can unwrap it with their password.
  • Invite links carry the note key in the URL #fragment, which is never sent to the server by browsers (per the HTTP specification).
  • The note owner can revoke access at any time, which re-keys the note with a new random key and re-wraps it for remaining collaborators.
  • Live updates use Supabase Realtime — changes are encrypted in transit and at rest. The server relays encrypted blobs; it never sees plaintext.

Authentication & MFA

Authentication is handled by Supabase Auth, which provides:

  • Email + password authentication with server-side bcrypt hashing.
  • JWT-based session tokens that are automatically refreshed.
  • Optional TOTP-based two-factor authentication (Time-based One-Time Password, RFC 6238) that can be enabled from Settings. When enabled, login requires both your password and a 6-digit code from an authenticator app.
  • Row-level security (RLS) policies on the database ensure that authenticated users can only access their own data, even if the API is called directly.

Threat Model

PrivyPad's security model protects against the following scenarios:

Protected against

  • Server breach — encrypted blobs are useless without user passwords.
  • Database leak — same as above; all note content is ciphertext.
  • Network eavesdropping — HTTPS + client-side encryption means intercepted data is doubly protected.
  • Rogue server administrator — the server never has access to plaintext or keys.
  • Rainbow table attacks — per-user salts make precomputed tables useless.
  • GPU/ASIC brute-force on passwords — Argon2id's memory-hardness makes this prohibitively expensive.

Not protected against

  • A compromised device (keylogger, malware) — if an attacker controls your browser, all bets are off.
  • A weak password — Argon2id slows down attacks but cannot prevent them if the password is trivially guessable.
  • Lost password — there is no recovery mechanism by design. If you lose your password, your data is permanently inaccessible.

Open Standards

PrivyPad relies exclusively on open, well-audited standards. No proprietary or custom cryptographic algorithms are used.

AES-256-GCMNIST SP 800-38D
Argon2idRFC 9106
Web CryptoW3C Recommendation
TOTPRFC 6238

Questions about our security model? Reach out via team@privypad.com. To report a vulnerability, see our responsible disclosure policy.