CLOSE
Updated on 21 Dec, 202517 mins read 17 views

Introduction

In a zero-knowledge password manager, there is exactly one secret that truly matters: the master password.

Every security guarantee, cryptographic operation, and trust assumption ultimately depends on how a single secret is treated. If the master password is weak, mishandled, or misunderstood, the entire systems collapses.

This chapter explains why the master password is different from all other passwords and how is becomes the root of trust for the entire system.

Not Just Another Password

It is tempting to think of the master password as:

  • A login password
  • A user authentication credential
  • A normal secret stored somewhere securely

This mental model is wrong.

The master password is not used to log in to a server. It is not verified directly. It is never stored.

Instead, it is raw cryptographic material.

Root of Trust Explained

A root of trust is a minimal set of elements that must be trusted absolutely because everything else depends on them.

In this system:

  • If the master password is compromised -> everything is compromised
  • If it is forgotten -> everything is permanently lost
  • If it is weak -> brute-force becomes possible

There is no higher authority that can fix a broken root of trust.

Why the Master Password Must Never Leave the Client

Sending the master password to a server would immediately violate zero-knowledge guarantees.

If transmitted:

  • It could be logged
  • It could be intercepted
  • It could be reused by insiders

Even hashing it on the server is unacceptable.

The master password must exist only in user-controlled memory, and only long enough to derive keys.

Key Derivation, Not Storage

The master password is never stored or compared.

Instead, it is used as input to a key derivation function (KDF) that produces:

  • Encryption keys
  • Authentication material

Key properties of this process:

  • Deterministic: same input -> same output
  • Slow: resistant to brute-force attacks
  • Salted: unique per user

Once keys are derived, the master password should be discarded from memory.

Why Traditional Authentication Fails Here

In a conventional system:

  1. User sends password to server
  2. Server hashes and compares it
  3. Access is granted if hashes match

This model fails in a zero-knowledge system because:

  • The password must never leave the client
  • The serve must not gain material usable for decryption
  • A database breach must not enable offline attacks

We need a different approach.

The Role of Deterministic Proofs

The server needs a way to verify that the client:

  • Knows the correct master password
  • Without learning the password itself

This is achieved through deterministic, derived proofs.

High-Level Idea

  1. Client derives an authentication key from the master password
  2. A verifier derived from that key is stored on the server
  3. On login, the client recomputes the verifier
  4. The server compares values – nothing more

The server verifies knowledge, not content.

What the Server Stores

In a correct design, the server stores only non-sensitive, derived data.

Typically:

  • A unique salt per user
  • An authentication verifier (derived value)
  • An encrypted vault blob

Crucially, none of these allow:

  • Decrypting the vault
  • Reconstructing the master password

A server breach reveals data – but not secrets.

What Happens During Signup

On your device

  1. You choose master password
  2. Device generates random salt
  3. Device derives auth key
  4. Device derives vault key
  5. Device encrypts empty vault

Sent to server:

  • Salt
  • Auth verifier (derived value)
  • Encrypted vault

Never sent:

  • Master password
  • Vault key
  • Decrypted data

SIGNUP (Happens only once)

Input:

User enters their master password.

Master Password = "correct horse battery staple"

Step-by-step on the Client (browser / app)

Step 1: Generate a random salt

salt = random(16-32 bytes)

Example:

salt = "A9F3C82D..."

Salt is NOT secret.

Step 2: Derive an AUTH KEY (slow function)

authKey = KDF (masterPassword, salt)

Think:

“Run password through a slow grinder”

Example:

authKey = "9c71fa..."

Step 3: Create a VERIFIER

verifier = HASH(authKey)

Example:

verifier = "b4e2d9..."

This is what the server will store.

Server CANNOT reverse this.

Step 4: Send data to SERVER

SEND → { email, salt, verifier }

What the server stores:

StoredWhy
emailidentify account
saltallow recomputation
verifierauthenticate later

LOGIN (Happens every time)

Step 1: User enters password again

Input: "correct horse battery staple"

Step 2: Server sends SALT back

SERVER → salt = "A9F3C82D..."

Server does this because:

Without salt, client cannot recompute anything

Step 3: Client recomputes AUTH KEY

authKey = KDF(masterPassword, salt)

Important:

  • Same password
  • Same salt
  • Same KDF
    • Same authKey

Step 4: Client recomputes VERIFIER

verifier = HASH(authKey)

This verifier will be identical to signup time.

Step 5: Client sends verifier

SEND → verifier

Step 6: Server compares

if (verifier == storedVerifier):
    login success
else:
    reject
  • Server never knew the password
  • Server only checks equality

 

Buy Me A Coffee

Leave a comment

Your email address will not be published. Required fields are marked *

Your experience on this site will be improved by allowing cookies Cookie Policy