Staging — blog preview only.
Skip to content

Wrong password must fail closed

Scheduled

8 min read By NT²

Unlock is not a best-effort decrypt of everything you own. NT² checks a small local verifier first. Wrong password fails closed: the vault stays locked, and the UI stays honest.

Wrong password must fail closed

Claim: unlock is a gate, not a hope

NT² Vault treats a wrong master password as a closed door, not a soft failure.

When you unlock, the device does not open every encrypted item “to see if it looks right.” It does not decrypt a sample note and guess from garbled UTF-8. It does not let a thrown DOMException become a blank screen that might leave session state half-initialized. Unlock is a deliberate gate: derive key material from the password you typed, authenticate a small local check value, and only then bring the vault into an unlocked session.

That gate must fail closed. Wrong password → vault remains locked. Damaged verifier → vault remains locked. Any decrypt that cannot authenticate → treat the operation as failed, show a clear error, and keep ciphertext opaque. The product may feel stubborn. It must not feel mysterious.

Fail closed is easy to say and easy to violate. Products ship “optimistic” unlock that proceeds until something looks wrong. Frameworks turn crypto errors into unhandled rejections. Support tools ask users to “try again after a refresh” when the real issue was a wrong password that partially mutated state. Each shortcut trades a crisp security property for a softer failure mode—and soft failure modes are how locked vaults become confused vaults.

NT² draws the line early: authentication of unlock comes before usefulness of content.

Constraint: fail-open crypto becomes unsafe UX

Password-based vaults sit on an awkward boundary. The master password is a human secret. The ciphertext is machine material. The UI must translate cryptographic outcomes into language people can act on. That translation is where many designs drift toward fail-open behavior.

Consider what “try decrypting and see” implies. AES-GCM is authenticated encryption: a wrong key should not produce plausible plaintext with a valid integrity tag. That property is a gift. It means Web Crypto can reject a wrong password during a controlled check instead of inventing readable garbage. If the product ignores that gift—catching nothing, catching too late, or continuing after a failed unwrap—the user experience becomes the security model:

  • An unhandled decrypt error can crash the unlock flow mid-way, leaving keys, flags, or route state that look “almost unlocked.”
  • A half-open session can expose list chrome, titles, or empty editors while payloads still refuse to open—teaching users that “locked” is negotiable.
  • A crash-as-UX path trains people to refresh, force-quit, or re-enter passwords until something sticks. Attackers love ambient retry culture; legitimate users learn that errors are noise.

There is a related trap on the success side. If unlock succeeds only when the first item decrypts, the vault has no independent password check. Corruption in one object masquerades as a wrong password. Conversely, if unlock dumps the user into the app before any authentication completes, wrong passwords become a navigation problem instead of an access control problem.

Fail closed means choosing a failure mode before those ambiguities appear. The system needs a dedicated unlock check that does not depend on opening the user’s entire archive. It needs decrypt paths that treat authentication failure as expected input, not an exceptional crash. And it needs UI copy that says “wrong password” or “could not unlock” without implying that the vault might be readable underneath a broken shell.

Offline guessing remains possible once someone copies local unlock material. Fail-closed unlock does not invent online rate limits for a stolen device profile. What it does is keep the application honest about the boundary: until the verifier authenticates, there is no unlocked vault—only a locked one and a rejected attempt.

Design: local verifier, then sealed decrypts

The unlock check is intentionally small.

When a vault is created, the device stores a password verifier with the local vault profile: an AES-GCM ciphertext of a known plaintext, sealed under key material derived from the master password and the vault’s local KDF salt. The verifier is not a hint. It is not a second copy of your password. It is not uploaded so a server can score guesses. Its job is narrow—answer one question on the device: does this password-derived key open the check value?

Unlock then looks like a short sequence:

flowchart TD
  A[Enter master password] --> B[Derive key material locally]
  B --> C[Decrypt password verifier with AES-GCM]
  C -->|auth fails / throws| D[Fail closed: stay locked]
  C -->|known plaintext ok| E[Continue unlock factors]
  E --> F[Unlocked session in memory]
  F --> G[Decrypt items and attachments only as needed]
  G -->|any decrypt fails| H[Catch: refuse plaintext / show error]

A few properties matter more than the diagram’s boxes.

Known plaintext is deliberate. The verifier encrypts a fixed, product-defined check value—not a user note, not a title, not a random blob whose “success” would be hard to define. After AES-GCM authentication succeeds, the plaintext must match what the vault expects. Wrong password fails authentication or fails the match. Either way, unlock stops.

The verifier lives with local unlock material. Salt and verifier stay on the device with the vault profile. That is the same custody story as keeping the KDF salt off the edge: the cloud does not become a password-check desk. Local unlock can succeed offline. Cloud sync, when used, still requires a separate cryptographic identity proof; it does not substitute for the verifier.

Every decrypt path wraps Web Crypto in try/catch. Unlock is the first consumer, not the only one. Opening an item, unwrapping a per-object content key, reading an attachment envelope, validating a share package—each of those operations can fail for honest reasons: wrong key, truncated blob, bit flip, user mismatch. The defensive rule is uniform: catch the failure, refuse to treat bytes as plaintext, surface a user-facing error, and leave the rest of the session consistent. A single bad object must not take down the unlocked shell as an unhandled exception. A wrong password at the gate must not become a stack trace the user has to interpret.

Fail closed is also a session rule. If verification fails, no vault AES key is installed into session memory, no “unlocked” route wins by accident, and no partial factor state is left looking like success. Locking later clears live keys; failing unlock should never have installed them.

This design pairs with envelope encryption and portable ciphertext shapes. The verifier decides whether the vault key path may proceed. Per-object content keys decide which sealed payloads open afterward. Structured fields leave RAM as sealed blobs. The verifier does not replace those layers; it keeps them behind a door that does not ajar itself on a typo.

Trade-off: honesty costs a softer “maybe”

Fail closed has product costs.

Users who mistype a long passphrase see a hard rejection instead of a half-loaded vault that “might still work if I click around.” That is correct security communication and a worse short-term feeling. Support cannot peek at ciphertext and tell someone which character was wrong. Corruption of the local verifier can look, from the outside, like a wrong password—because both fail the same gate. Distinguishing “wrong secret” from “damaged profile” needs careful copy and recovery tools the user already holds, not a server oracle.

There is also engineering discipline. Every new decrypt site is a place someone might forget the try/catch, rethrow raw crypto errors into the UI framework, or log sensitive failure detail. Fail closed is a habit, not a single function. Tests have to cover wrong-password unlock, not only the happy path. Error strings have to stay boring on purpose: they must not become side channels that say “salt missing,” “share three failed,” or “item 47 is readable.”

We accept that friction because the alternative is worse. A vault that sometimes unlocks into a broken world teaches users to ignore lock state. A vault that crashes on wrong password teaches users that security errors are bugs. Neither lesson belongs in a product that stores credentials, notes, and identity documents.

The trade is therefore specific: sharper unlock failures, more careful error handling, and less magical recovery theater—in exchange for a session model where “locked” means locked.

What we refuse

We refuse unlock-by-sampling-content. Opening random items to decide whether the password was right couples unlock to data health and invites ambiguous partial success.

We refuse crash-as-UX for expected crypto failure. Wrong password and failed authentication are normal outcomes. They must become clear UI states, not unhandled exceptions.

We refuse a half-unlocked session. No vault key in memory, no “you are in” chrome, no editable shells over ciphertext that never authenticated at the gate.

We refuse uploading the verifier so support can check guesses. A local check value that becomes a cloud oracle stops being a custody boundary.

We refuse silent fallbacks that “decrypt somehow.” No legacy soft-fail path that skips authentication because an older build used to. No best-effort plaintext decode after AES-GCM rejects the tag.

We refuse treating UI resilience as optional polish. try/catch around decrypt is part of the security boundary: it keeps failure modes fail-closed instead of fail-spectacular.

Close: the door that does not ajar

A password verifier is a small ciphertext with a large job. It lets the device reject a wrong master password before the vault pretends to open. Fail-closed decrypt handling keeps every later operation honest when keys, blobs, or envelopes disagree with reality. Together they turn “zero-knowledge” from a brochure word into a daily unlock experience: locked stays locked until the check passes.

That check sits on the same boundary as keeping the KDF salt on your device and refusing provider password reset. It complements keys that must not survive refresh: even a correct password only installs live key handles for a session that can still be cleared. And once unlocked, content still opens one sealed object at a time—envelope encryption per object, with structured fields leaving RAM as CBF.

If you want a vault whose wrong-password path is boring on purpose, try NT² Vault or read more at nt2.me.

Last updated 2026-09-26

Related stories