1. Client sends its username u to server.
  2. Server extracts a tuple in the form of (username, salt, hashed_password) from its database, where username matches the client's username u. hashed_password is the result of hash(salt + password) (where hash is a modern cryptographic hash function) which has been computed when the tuple has been written to the database (e.g. during user registration).
  3. Server sends salt to client.
  4. Client computes h := hash(salt + password) and sends h to the server.
  5. Server compares h with hashed_password and grants access if the hashes match.

If we assume that the server has not computed the hash during the user's registration (instead, the client computed the hash and sent the tuple (username, salt, hashed_password) to the server in order to store it in the database), why is this scenario not considered a zero knowledge password proof? Or is it in fact a ZKP?

From my understanding the server has never seen the actual password, but it can be verified that the client posses the original password which was used to create the initial hash.

2 Answers 2


The main problem of your protocol is that the client's 2nd answer is vulnerable to replay attacks. During the login procedure, an attacker learns u and h which can both be reused later in a malicious login by the attacker and will result in a successful login.

I'd recommend using challenge-response authentication with HMAC here, which means the client receives a challenge from the server and returns the HMAC signed challenge (= response).

  • Assuming the client knows the password, the client is able to sign messages with it (symetrically using HMAC)
  • From the server point of view, the client authenticates itself by signing a message given from the server

Naive protocol to understand the idea:

1. [C] –––(username)–––> [S]

Attacker: learns username (you might want to change that eventually)

2. Server calculates M = (nonce) and stores M

nonce: a bunch of random bytes which MUST be unique, prevents replay attacks. To make it unique, append a timestamp or login counter for example.

2. [C] <––– M ––– [S]

Passive attacker: The attacker learns M which is different for every login attempt, even for the same user. Without knowing the password, the attacker cannot sign it.

Active attacker: manipulating M doesn't help anything: The client will sign the wrong M which won't be accepted by the server later.

3. [C] ––– HMAC(M, pw) –––> [S]

Passive attacker: learns the signature HMAC(M,pw). The HMAC signature cannot be reused because M is always different (this is why it must be unique).

Active attacker: Manipulating M or the HMAC signature causes the signature to be invalid or not matching the server-stored M in step 4.

4. Server examines if the received M equals the stored M and verifies the HMAC signature

This is possible because the server also knows the password.

This protocol satisfies my interpretation of wikipedia's very loose definition of ZKPP as it is interactive and the client proofs knowledge of password-derived data and not the password itself.

Generally, the security level of zero knowledge proofs is based on iterative procedures which my naive attempt doesn't cover. I'd recommend to take a look at CHAP and/or SRP.

  • Good answer. But I believe you should talk about why the OPs algorithm is not Zero knowledge password proof.
    – Limit
    Commented Feb 1, 2017 at 14:30

Your example removes the notion of hashing altogether: H(S+P) becomes a cleartext password that can directly be reused without any extra work.

  • you're totally right, thank you. What would I have to change in order to make use of ZKP? I'm also considering that the data is transmitted over a secured and authenticated channel between the client and the server.
    – watain
    Commented Feb 1, 2017 at 8:58
  • @watain My gut instinct would be to hash the password on the client (perhaps using the username as a salt to avoid having to sent the salt client-side, or use a separate salt), then hash it again server-side. Commented Feb 1, 2017 at 11:28
  • 2
    Hashing on the client side would require the server to send a one-time challenge or you're falling for the same problem: always using the same cleartext as password. This would require the server to know the password in turn which would be incompatible with storing only the salted hash in the DB. Generally speaking, implementing challenge-response is hardly ever worth it: it's better to use a secure challel (SSL) and store the password using a proper storing strategy.
    – Stephane
    Commented Feb 1, 2017 at 13:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .