Write freely.
The server can’t read it.

Obscura encrypts every note in your browser before it leaves your device. The server stores ciphertext only: no keys, no plaintext, no way in, even with full database access.

Open source and self-hostable, so the privacy is verifiable.

Your browser
Plaintext

Q3 plan: the privacy bet

Competitors can’t match our model without giving up server-side access. Lead with that.

syncs as
The server
Ciphertext only

9f3a2c8e0d1b4a7f5e2c9d6b3a0f7e4c1d8b5a2f9e6c3d0b7a4f1e8c5d2b9a6f3e0c7d4b1a8f5e2c9d6b3a0f7e4c1d8b5a2f9e6c3d0b7a4f1e8c5d2b9a6f3e0c7d4b1a8f5e2c9d6b3a0f7e4c1d8b5a2f9e6c3d0b7a4f

Without your password, this is just bytes.

  • EncryptionAES-256-GCM
  • Key derivationPBKDF2 · SHA-256
  • Iterations600,000
  • Keys heldClient-side only
  • SourceFully open

The threat model

“End-to-end encrypted” means very little if the server holds your keys.

Most note apps encrypt in transit and at rest, then keep a key on the server to power search, sync, or recovery. That means a breach, a subpoena, or an insider can turn your notes into plaintext. Obscura is built so the key is never on the server at all.

Capability
  • Notes encrypted in transit (TLS)Obscura
  • Notes encrypted at rest on the serverObscura
  • Server never holds the decryption keyObscura
  • Stays secret if the full database leaksObscura
  • Stays secret under a subpoena or admin accessObscura
  • You can read the code that does all thisObscura

The difference is structural, not promotional: because your master key is derived from your password and never leaves the browser, the server physically cannot decrypt your notes.

The chain

From thought to ciphertext, four steps.

Your password never leaves your device. Here is the exact path a note takes, the same path you can read in the source.

  1. 01

    You type a password

    It never leaves your browser. PBKDF2 derives a key from it using 600,000 iterations of SHA-256.

    password → PBKDF2 → key
  2. 02

    It unlocks your master key

    Your master key is stored encrypted on the server. The PBKDF2 key decrypts it, in memory, as a non-extractable CryptoKey.

    wrapped key → decrypt → master key
  3. 03

    Each note is encrypted

    AES-256-GCM with a fresh 12-byte IV per note, run entirely in the browser via the Web Crypto API.

    note + key + IV → AES-GCM
  4. 04

    Only ciphertext syncs

    The server stores opaque encrypted blobs. Even with full database access, your notes stay unreadable without your password.

    ciphertext → server → just bytes
lib/crypto.ts
async function encryptNote(
  content: string,
  masterKey: CryptoKey
) {
  // 12-byte initialization vector, fresh and random per note
  const iv = crypto.getRandomValues(
    new Uint8Array(12)
  );
  const encoded = new TextEncoder().encode(content);

  // AES-GCM, entirely in the browser
  const ciphertext = await crypto.subtle.encrypt(
    { name: "AES-GCM", iv },
    masterKey,
    encoded
  );

  return { ciphertext, iv }; // only this leaves the device
}

Open source

Privacy you can read, not just a promise.

The encryption layer, the client, and the server are all open source. Verify the cryptography yourself. This is the actual function that encrypts every note.

  • AES-256-GCM encryption in the browser
  • PBKDF2 key derivation, 600,000 iterations
  • Fresh random IV per note
  • Master key held as a non-extractable CryptoKey
  • Zero server-side access to content

Self-host

Run it yourself, in minutes.

Because encryption never depends on the server, hosting it yourself doesn’t weaken anything. Same primitives, your infrastructure, your data.

terminal

$ git clone github.com/thepushkaraj/obscura

$ cd obscura

$ cp .env.example .env.local

# Add your Supabase credentials to .env.local

$ npm install && npm run dev

Running on http://localhost:3000

Your ideas deserve a private home

Start writing where no one else can read.

No tracking. No server-side keys. Free, open source, and encrypted by default.