DEV Community

supi sula
supi sula

Posted on • Edited on

Why Does SCRAM Authentication Take This Form?

Introduction

One form of password-based authentication is SCRAM (Salted Challenge Response Authentication Mechanism). SCRAM is a type of challenge-response authentication that uses passwords. It achieves the following:

  • The server can verify that the client possesses the same knowledge as when the password was registered.
  • The client can verify that the server possesses the knowledge entrusted to it at the time of password registration.
  • At no point — during registration or authentication — is there any need to expose the plaintext password outside the client, i.e., the password is never sent to the server.

Because the server is never told the password, even if the password is reused elsewhere, the server cannot misuse it.

(This article is a translation of a Japanese article written by the author themselves.)

Overview of SCRAM Authentication

For a detailed description of the SCRAM protocol, refer to this article (in Japanese).
My post focuses not on protocol specifics, but on the information known only to the client or server, and the role of one-way function in the computations.

Computation Flow of Key Values in SCRAM

Below is a diagram showing the information involved in SCRAM and the direction of their derivation.
Rectangles represent data; bold arrows represent one-way function; ⊕ denotes XOR. The arrow direction indicates ease of computation.

Colors indicate data types:

  • Orange: Secret information that must not be disclosed by the client
  • Green: Information stored on the server
  • Yellow: Per-session information

Computation flow in SCRAM authentication
Diagram: Computation flow in SCRAM authentication

(This diagram is a reconstruction based on one found in the previously referenced blog post, customized to reflect my own focus.)

Password Registration

When a password is registered, the client derives a SaltedPassword from the plaintext password along with a salt and iteration-count. Both the password and SaltedPassword must remain secret.

From the SaltedPassword, two keys — ClientKey and ServerKey — are derived, using HMACs with fixed labels "ClientKey" and "ServerKey". Then, ClientKey is hashed to produce StoredKey, and both StoredKey and ServerKey are stored on the server, along with the salt and iteration count. (*1)

This computation can be done server-side, but may also be performed on the client, which then sends only the results to the server. If all computations are client-side, the server knows only StoredKey and ServerKey, and cannot derive ClientKey, SaltedPassword, or the original password due to the one-way nature of the functions involved.

The “knowledge entrusted to the server” during registration refers to the pair of StoredKey and ServerKey.

Password registration
Diagram: Password registration

During Authentication

SCRAM authentication consists of two message exchanges initiated by the client.

The first exchange constructs AuthMessage, which functions as a challenge for both client and server. It includes a client-generated and server-generated nonce, ensuring the message is unique per session.

The second exchange performs the main authentication, with response computation, transmission, and verification.

The client sends ClientProof, asserting it has the same knowledge as during registration.

The server sends ServerSignature, asserting it possesses the entrusted knowledge.

Creating and Verifying ClientProof

The client, knowing the password, can compute SaltedPassword, ClientKey, and StoredKey (*2). Using AuthMessage, it calculates ClientSignature, then derives ClientProof via XOR with ClientKey, and sends this to the server.

Client creating ClientProof
Diagram: Client creating ClientProof

The server, knowing StoredKey and AuthMessage, computes ClientSignature, then XORs it with the received ClientProof to recover ClientKey. It re-derives StoredKey and verifies it against the stored value.
If this matches the stored StoredKey, the server can conclude that the client in this authentication session was able to compute the correct ClientKey — that is, the client knows ClientKey.
Since computing ClientKey requires the original password, the server interprets this as evidence that the client still possesses the same knowledge as at the time of password registration.
Of course, this interpretation is based on the assumption that knowing ClientKey is equivalent to knowing the password. This is considered an intentional design trade-off in SCRAM.

Server verifying ClientProof
Diagram: Server verifying ClientProof

Creating and Verifying ServerSignature

The server computes ServerSignature from its stored ServerKey and the session's AuthMessage.

Server creating ServerSignature
Diagram: Server creating ServerSignature

The client, using its computed ServerKey and AuthMessage, calculates ServerSignature and compares it to the received one. A match confirms that the server knows ServerKey and is thus authentic.

Client verifying ServerSignature
Diagram: Client verifying ServerSignature

The Implications of the Server Being Able to Derive ClientKey

Although ClientKey is not stored on the server, it is reconstructed during successful authentication. Possession of ClientKey allows the server to compute valid ClientSignature and ClientProof for any session — effectively making ClientKey equivalent to the password in terms of credential power.

What the Server Can Do with ClientKey

Once the server reconstructs ClientKey, it can theoretically:

  • Log in to itself as the user
  • Log in to a different server (B) as the user, if the same password, salt, and iteration count are used on both servers A and B

In theory, it also allows:

  • Server A impersonating user X to itself — Since this is a legitimate connection, user X may not be able to deny this connection
  • User X denying a connection to server A for the same reason

Is Server Use of ClientKey an Abuse?

Although password reuse is a user responsibility, matching salts and iteration-counts are rare (*3). Logging into another server using ClientKey typically occurs in intentionally credential-sharing environments, like server clusters.

Thus, such usage may not constitute abuse.

Is This a SCRAM Vulnerability?

The fact that ClientKey is reconstructible is a consequence of its role in authentication. The ability to generate ClientProof from ClientKey is an expected feature, not a flaw.

Questions and Answers

Why Doesn’t the Server Store ClientKey?

If the server ends up reconstructing ClientKey, why not store it instead of StoredKey?

A: StoredKey is stored long-term, whereas ClientKey is only briefly reconstructed. Because ClientKey is a full credential, storing StoredKey instead limits exposure risk.

Why Not Just Send ClientSignature?

Why does the client need to send ClientProof instead of just ClientSignature?

A: Accepting ClientSignature as proof would mean treating knowledge of StoredKey as equivalent to client identity. Since StoredKey is long-term and stored on the server, this weakens security — akin to storing passwords directly. ClientProof, requiring knowledge of ClientKey, avoids this issue.

Why Not Use MAC with ClientKey Instead?

Why not just use ClientKey to MAC the AuthMessage directly and treat that as "ClientSignature"?

A: In that case, the server couldn’t verify it, since it doesn’t know ClientKey.
So how can a server that only knows the StoredKey verify that the client in this authentication session knows the upstream value (ClientKey) of the one-way function? To solve this problem, the bidirectionality of the XOR operation*4 is used. It is not possible to calculate the inverse function of a one-way function, but the bidirectionality of the XOR operation makes it possible to calculate the upstream value.

Why Is ServerSignature Needed?

Why not use ClientSignature for server authentication too?

A: ClientSignature requires StoredKey or ClientKey. The client’s ClientProof alone doesn’t allow the server to recover either. Therefore, the ability to compute ClientSignature implies possession of StoredKey. Still, using a distinct ServerKey and ServerSignature clarifies the structure.

Conclusion

SCRAM authentication never requires the client to reveal the plaintext password—either during registration or authentication.

However, it’s important to note that ClientKey, a secret that fully serves as a credential, can be reconstructed by a legitimate server (that knows StoredKey) during authentication. This differs from public-key challenge-response schemes.

On the other hand, a non-legitimate server (without StoredKey) cannot obtain ClientKey. This sharply distinguishes SCRAM from hash-based authentication schemes that indiscriminately expose credentials to all servers.

Footnotes
*1: The SCRAM standard requires both to be stored. If the client remembers them, storage on the server isn’t strictly necessary for mutual authentication.

*2: The salt and iteration count are sent from the server during the first exchange.

*3: This can happen with improper implementations, such as using the user name as a salt.
*4: XOR has the reversible property: X XOR Y = Z implies X XOR Z = Y and Y XOR Z = X.

Top comments (0)