SigNoteSigNote
Documentation

Seals 🛡️

Seals are the highest-security tier in SigNote. Each Seal is encrypted with its own unique key — completely independent from every other note. They're designed for your most sensitive information.


How Seals differ from Secrets

Secrets use a single shared session key to encrypt all bodies. That's convenient — unlock once, read everything — but it means a single key covers all your secrets.

Seals take a different approach: each note has its own Note Encryption Key (NEK), generated fresh when the note is created. Seals are never decrypted in bulk. You open one, read it, and close it. The decrypted content doesn't linger in memory.

Secrets 🔒Seals 🛡️
Encryption keyOne shared session keyUnique key per note
DecryptionAll bodies on unlockOne at a time, on demand
MemoryAll bodies in memory during sessionOnly the open note
Blast radius if key compromisedAll secretsJust one note

How a Seal is encrypted 🔐

When you save a Seal, here's what happens cryptographically:

  1. A random 32-byte Note Encryption Key (NEK) is generated
  2. The note body is encrypted with the NEK using AES-GCM 256-bit (the note ID is used as Additional Authenticated Data)
  3. A seal wrapping key (sealWrapKey) is derived from the MEK using HKDF — crucially, the note ID is part of the derivation input, making it unique to this note
  4. The NEK is wrapped (encrypted) with sealWrapKey, also using AES-GCM with the note ID as AAD
  5. The encrypted body and the wrapped NEK are both stored in Postgres

The server never sees the plaintext body or the NEK.


How a Seal is decrypted

When you open a Seal:

  1. Derive sealWrapKey from the MEK + note ID (same HKDF derivation as during encryption)
  2. Unwrap the NEK using sealWrapKey
  3. Decrypt the body using the NEK

If the note ID doesn't match the AAD used during encryption, decryption fails — this cryptographically binds the ciphertext to its specific note.


Re-encrypting after viewing

After reading a Seal, you can re-encrypt it manually using the Encrypt button. This discards the decrypted content from memory and the note returns to its locked state. It's a good habit for your most sensitive notes.

A 60-second countdown timer also re-encrypts the note automatically if you leave it open without editing.


Auto-lock 🔓

SigNote has two levels of automatic locking to protect your Seals when you're not actively using them.

Soft lock — tab hidden

When you switch away from the tab (or minimise the window), SigNote immediately clears the MEK from memory. If a Seal is open and decrypted, it is automatically re-encrypted in place — the modal stays open but returns to the encrypted placeholder view. Your deviceShare is kept in sessionStorage.

When you return to the tab and click Decrypt again, the MEK is silently reconstructed from deviceShare without asking for your passphrase. The Seal decrypts directly.

If no Seal is open, clicking Unlock on the page also re-unlocks silently.

Hard lock — inactivity or sleep

A hard lock occurs when:

  • You click the Lock button explicitly
  • The tab has been inactive for 5 minutes (no mouse, keyboard, or touch input)
  • The device goes to sleep (detected when the tab resumes after a gap of 30+ seconds)

On hard lock:

  • The MEK is cleared from memory
  • The deviceShare is cleared from sessionStorage
  • Any open decrypted Seal modal is closed immediately
  • All encrypted content is inaccessible until you enter your passphrase again

The AAD binding

Additional Authenticated Data (AAD) is a feature of AES-GCM. Data included as AAD is authenticated but not encrypted — if it doesn't match what was used during encryption, decryption fails with an authentication error.

SigNote uses the note ID as AAD on both the body encryption and the NEK wrapping. This means:

  • A ciphertext extracted from one Seal can't be decrypted as if it were another
  • Cross-note attacks require corrupting the note ID, which is detectable

Search

Seals can be searched by title only. Like Secrets, the bodies are encrypted and the server can never index them.


Technical details

  • Algorithm: AES-GCM 256-bit (both for body and for NEK wrapping)
  • NEK: 32 random bytes, generated fresh per note
  • Wrap key: HKDF from MEK with info string signote-v1/seal-wrap/<noteId>
  • AAD: Note ID (used on both body encryption and key wrapping); attachments use seal-file:v1:<noteId>
  • Stored: encryptedBody + wrappedNoteKey in Postgres; attachment ciphertext in object storage

→ Full cryptographic details in Encryption.

→ Understanding the threat model? See Threat model.


File attachments 📎

Files attached to a Seal are encrypted in the browser with that Seal's own NEK — the same key as its body — and bound to its note ID. The server receives only ciphertext, and a file belongs to its Seal the way the body does: it can't be opened with another Seal's key, pasted into another note, or linked to one.

Uploading is blocked if encryption is locked — you must unlock first.

Moving a Secret to Seals re-encrypts its attachments under the new Seal's key as part of the move. Attachments added to a Seal before files were keyed this way are still under the account's attachment key; they move onto the Seal's own key the next time you change your encryption keys.

→ Full details in File uploads