Salted Challenge Response Authentication Mechanism (SCRAM) SHA-1






4.94/5 (20 votes)
A C# implementation of the SCRAM SHA-1 (RFC 5802) authentication protocol.
Introduction
Two fundamental qualities necessary for security assurances over a telecommunication channel are confidentiality and authentication. Confidentiality assures that only the right parties have access to the communication stream, and authentication attempts to guarantee that the parties at each end of the communication channel are who they say they are. The Salted Challenge Response Authentication Mechanism (SCRAM) SHA-1 is a standardized authentication technique defined in RFC 5802. This article discusses this mechanism briefly using the codes attached.
The primary motivation for this work was that I was unable to find a full C# implementation of the SCRAM-SHA1 protocol for use on the project I am currently working on and so I decided to implement it myself. Hopefully, you wouldn’t have to go through the minor hassle of writing a C# implementation if you ever needed it.
You are welcome :D
Background
The primary means to authenticate oneself to an entity is to show that one holds some restricted or secret information that can be presented when challenged. Typically, within the context of Information and Communication Technology (ICT), one presents a user name and/or a password that authenticates one to the challenging entity. Sometimes the authentication process has to be mutual i.e., party A authenticates herself to party B and party B authenticates himself to party A.
SCRAM SHA-1 belongs to a class of protocols that provide the mutual authentication facility. Another similar protocol is the Socialist Millionaire Protocol (SMP) discussed here . In SCRAM SHA-1, as with most secure authentication mechanisms, the password or secret information is never transmitted during the execution of the protocol. Instead, the secret information in addition to a cryptographically secure random value is used to compute another value at each end of the communication channel. It is this computed value that is transmitted. On receipt of the transmitted value the communicating parties compare their computed value to the received value. If these values match then the authentication process is successful, otherwise it fails.
The SCRAM SHA-1 Mechanism
The SCRAM SHA-1 protocol assumes that one end of the communication channel is the client and the other end is a server. Keep this in mind as you read the rest of the article.
The SCRAM SHA-1 Message Sequence

The execution of SCRAM SHA-1 involves the transmission and processing of four messages; two each by/for the client and server. As can be seen in the image above, the client begins the process by sending the Client First Message and in response to the reception of a validly formatted first message from the client, the server sends the Server First Message to the client. The client processes this message and if everything is okay, it transmits the Client Final Message. The server, as expected, processes this message. At the end of this task, the server should know if the client is successfully authenticated or not. If it is, the server sends the Server Final Message, otherwise it sends an authentication failure message to the client (or maybe not). With the reception of the Server Final Message, the client is also able to authenticate the server.
The SCRAM SHA-1 Cryptographic Values
There are four cryptographic values that are central to the SCRAM SHA-1 protocol. These values are;
-
Client nonce: This is a value that is randomly generated by the client, ideally using a cryptographic random generator. This value, along with the client’s user name, is contained in the Client First Message. Note that the client nonce value must be different for each authentication session.
-
Server nonce: This is similar to the client nonce and it is contained in the Server First Message. This value must be different for each authentication session and be cryptographically secure.
-
Salt: The Salt is a cryptographically secure random number generated by the server. This Salt value and the password are fed into a one-way cryptographic function that generates another value. Recall from the background section that this value was used to hide the password. The Salt is contained in the Server First Message.
-
Iteration Count: This is a numerical value generated by the server that indicates how many times the cryptographic function mentioned above should be applied to the Salt and the password to generate its output. This Iteration Count value is transmitted in the Server First Message.
Caveat
The SCRAM SHA-1 specification strongly advises that the protocol should be used in conjunction with another protocol that provides confidentiality. In other words, the SCRAM SHA-1 messages should be exchanged over an encrypted channel. The idea is to prevent an eavesdropper from extracting the contents of these messages in transit and then using the values contained within to mount an off-line dictionary attack to extract the password.
For the demo presented here, the Transport Layer Security (TLS) is used to provide confidentiality for the authentication protocol.
Using the code
The routines associated with the implemented SCRAM SHA-1 protocol are presented in this section. Also presented is the output for the authentication protocol using the test values (or vectors) given in the specification. This section ends by showing the outputs of both the client and the server when the implemented protocol runs over TLS.
The implemented SCRAM SHA-1 routines
// Client routines
string _user_name = "user";
string _password = "pencil";
string _message = string.Empty;
bool _is_server_authenticated = false;
// Initialize the protocol object
ScramSha1 _client = new ScramSha1(USER_MODE.CLIENT, _user_name, _password);
// Get the client’s first message
_message = _client.GetClientFirstMessage();
// The client sends the message to the server and waits for the server first message
// Assume that the server's first message has been received and is contained in _server_first_message
// Get the client’s final message
_message = _client.GetClientFinalMessage(_server_first_message);
// The client sends this final message to the server and waits for the server's final message
// Assume that the server first message has been received and is contained in _server_final_message
_is_server_authenticated = _client.VerifyServerSignature(_server_final_message);
if (_is_server_authenticated == true)
Console.WriteLine("The server is authenticated \n");
else
{
Console.WriteLine("The server is not authenticated \n");
// Send authentication failure message if it is the policy
}
This protocol implementation can be run in one of two modes: Server or Client. To begin the authentication process as a client, the class
constructor i.e., ScramSha1(USER_MODE, string,
string)
, is called. The constructor is passed
the parameters:
user mode, user name and password as shown in the code extract above.
The Client First Message is retrieved by calling the
GetClientFirstMessage()
routine. This message
is
sent to the server. As
soon as the Server First Message is received, the client passes it to
the GetClientFinalMessage(string)
routine.
This routine returns the
Client Final Message which is transmitted to the server. Finally,
the received Server Final Message is passed to the
VerifyServerSignature(string)
routine. The
bool value returned by this
routine indicates if the server has been authenticated or not.
The implementation sets the default length of the client nonce
to 32 bytes. In order to increase the difficulty for an off-line
dictionary attack, the client might want to increase the length of this
nonce. This can be done by instantiating the class in client mode using
the constructor ScramSha1(USER_MODE, string, string, int)
,
and passing it the desired length of the client
nonce.
If an error were to occur during the processing of the
received server messages then the GetClientFirstMessage()
and GetClientFinalMessage(string)
routines return an empty string. These errors could be as result of an
improperly formatted server message.
// Server routines
string _user_name = string.empty;
string _password = string.empty;
string _message = string.Empty;
bool _is_client_authenticated = false;
// Assume that the server has just received the first message of the client and it is contained on _client_first_message
// Initialize the protocol object
ScramSha1 _server = new ScramSha1(USER_MODE.SERVER, _client_first_message);
// Get the user name
_user_name = _server.GetUserName();
// Use the _user_name to get the associated password from the authentication database and set this value in _password.
// Get the server’s first message
_message = _server.GetServerFirstMessage(_password);
// The server sends the message to the client and waits for the client's final message
// Assume that the client's final message has been received and is contained in _client_final_message
// Get the server’s final message
_message = _server.GetServerFinalMessage(_client_final_message, ref _is_client_authenticated);
if (_is_client_authenticated == true)
{
Console.WriteLine("The client is authenticated \n");
//Send the server final message
}
else
{
Console.WriteLine("The client is not authenticated \n");
// Send authentication failure message if it is the policy
}
Executing the protocol in server mode follows the pattern
shown in the code extract above. Note that the constructor used in this
case differs from those used in the client mode. The server mode can
only be instantiated when the Client First Message has been received.
The received client message is passed to this constructor:
ScramSha1(USER_MODE, string)
. The server can
get the user name of the
client by calling the GetUserName()
routine.
The server uses this user
name to get the password from the authentication database. If it
exists, the password is passed to the GetServerFirstMessage(string)
routine. This routine returns a string containing the Server First
Message which is transmitted to the client. When the server receives
the Client Final Message, it passes it to the
GetServerFinalMessage(string ,ref bool)
routine. This routine
is also passed (by reference) a bool variable. If the bool variable
value is true
, then the client is
authenticated and the string returned
by this routine is sent to the client as can be seen in the code
extract above. Otherwise, an authentication failure message can be sent
instead.
The length of the server nonce as well as that of the Salt can
be set by calling the ScramSha1(USER_MODE, string, int,
int)
constructor in server mode. The reason for increasing the client nonce
also applies to the server nonce and Salt.
The GetServerFirstMessage(string)
routine returns an empty string when an error occurs
during the processing of the received client message. The GetServerFinalMessage(string ,ref
bool)
routine, on
the other hand, returns an empty string when an error occurs or when
the client is not authenticated.
In server mode, the lower and upper limits of the iteration
count can be set by calling the SetIterationCountLimits(int,
int)
routine. The default lower and upper
limits are 4000 and 5000, respectively. It is important that these
limits are not set too high or too low. Setting it too low improves the
chances of a successful off-line dictionary attack on this
authentication mechanism. If it is set too high, it might overwhelm a
client running on a limited processor device. In order to prevent a
malicious server from degrading the performance of a client device, the
client can set the maximum allowable number of iterations it can
accommodate by passing this value to the SetMaximumIterationCount(int)
routine. The default value
for this client maximum is 10000. If the iteration count received from
the server is above this maximum, the authentication process fails.
Executing SCRAM SHA-1 with Test Vectors
The SCRAM SHA-1 protocol RFC provides
values that are used to test the conformity of an implementation to the
authentication specification. Three things are required to run this
implementation using the test vectors: the UseTestVectors(bool)
static routine of the
class is called and passed a parameter true
to set the instance to test
mode. Secondly, the user name is set to “user”, and lastly, the
password is set to “pencil”. To see the output of the authentication
protocol in test mode, run an instance of the attached console
application, type the letter “T” and press enter. The screen should
give an output similar to that of the image below
.

Executing SCRAM SHA-1 over TLS
The TLS implementation used in this work was deliberately made inelegant in order to keep it simple enough to demonstrate the use of the authentication protocol over TLS.
The TLS implementation of the server is based on the SuperSocket class of Kerry Jiang. The server's SCRAM SHA-1 logic can be found in the ScramCommand
class. That of the client is contained in the SCRAMSha1TestClient
class.
To begin, an instance of the application should be run. Type the letter “S” and press enter to start it in server mode. Then run another instance and type the letter “C” and press enter to start it in client mode. If everything goes according to plan you should see the screen shots shown below.


To force the authentication process to fail you can set one password for the client and another for the server and observe the outputs.
History
17/12/2013: First version
26/03/2014: Made the client and the server TLS mechanisms more robust.