Subject: Comments on SCRAM

From: Nicolas Williams <[email-masked]>
Date: Mon, 18 Feb 2008 01:56:18 -0600

I think we can do better w.r.t. key hierarchy.

I suggest:

 o Replacing Hi() with something like PBKDF2 (see RFC2898), using HMAC()
   as the PRF:

   U0 := HMAC(Password, salt)
   U1 := HMAC(Password, U0)
   U2 := HMAC(Password, U1)
   ..
   Uc := HMAC(Password, Uc-1)

   Hi = U0 XOR U1 XOR U2 XOR .. XOR Uc

   This is, essentially, PBKDF2 with HMAC() as the PRF and with dkLen
   == output length of HMAC() == output length of H().  It's also very
   similar to the Hi() that is specified in the I-D.

   'c' here is the iteration count, of course.

 o Specifying a minimum iteration count.  This will require doing some
   performance measurements on various systems.

 o Adding an optional realm name that:

   a) can be sent by the client in the challenge request IF the client
      knows it

   b) can be sent by the server IF the client did not send it in the
      challenge request, AND IF there is a realm at all

   c) is part of the salt used in the derivation of what we might call
      the "master secret" for a {user, realm}

   This way if the client knows the realm name, it can use it, and if
   not, not.  The client, however, would need to know whether a realm
   name is known (e.g., the UI may need to ask the user if the
   server-provided realm name is correct).

 o Adding the server name to the derivation of the shared secret with
   the server

So that the result might look like this:

   MasterSecret := Hi(HMAC(password, salt + realm)

   RealmSharedSecret := HMAC(MasterSecret, "realm-shared-secret")

   ClientSecret := HMAC(MasterSecret, "client-secret")
   ClientSecretVerifier := H(ClientSecret)

   SharedSecret := HMAC(RealmSharedSecret, "shared-secret;" + server-name)
   ServerSecret := HMAC(RealmSharedSecret, "server-secret;" + server-name)

   AuthMessage := client-first-message + "," +
                  server-first-message + "," +
                  final-client-message-without-proof
   ClientSignature := HMAC(SharedSecret, AuthMessage)
   ClientProof := ClientSignature XOR ClientSecret
   ServerSignature := HMAC(ServerSecret, AuthMessage)

The server stores ClientSecretVerifier and ServerSecret.  The realm, if
there is one, stores RealmSharedSecret and ClientSecretVerifier.

This scheme allows the server to impersonate the client to itself after
the client authenticates to it once (but this is of little use to the
server), and it allows the realm to impersonate the client to all
servers in that realm once it has seen ClientSecret.

Also, we may want to define an error message in case the client
specifies a realm name unknown to the server, or in case the ClientProof
cannot be validated.

Nico
--