Skip to content

Using SRP 6a protocol

Alexey Yakovlev edited this page May 22, 2018 · 7 revisions

Quoting the Wikipedia article:

The Secure Remote Password protocol (SRP) is an augmented password-authenticated key agreement (PAKE) protocol, specifically designed to work around existing patents.

Like all PAKE protocols, an eavesdropper or man in the middle cannot obtain enough information to be able to brute force guess a password without further interactions with the parties for each guess. This means that strong security can be obtained using weak passwords. Furthermore, being an augmented PAKE protocol, the server does not store password-equivalent data. This means that an attacker who steals the server data cannot masquerade as the client unless they first perform a brute force search for the password.

In layman's terms, during SRP (or any other PAKE protocol) authentication, one party (the "client" or "user") demonstrates to another party (the "server") that they know the password, without sending the password itself, nor any other information from which the password can be broken. The password never leaves the client and is unknown to the server.

Zyan implementation notes

Zyan SRP-6a implementation is based on (and is compatible with) secure-remote-password npm module by Linus Unnebäck. This means you can use credentials generated by the npm module to authenticate your Zyan application (and vice versa).

To enable SRP-6a authentication, use the following classes:

  • SrpAuthCredentials — on the client side
  • SrpAuthenticationProvider — on the server side

Client-side code

var url = "tcpex://localhost:8090/MyServer";
var protocol = new TcpDuplexClientProtocolSetup(true);
var credentials = new SrpAuthCredentials("[email protected]", "secret");

using (var connection = new ZyanConnection(url, protocol, credentials, true, true))
{
	var proxy = connection.CreateProxy<ISampleServer>();
	...
}

Note that while you still provide user name and password to the SrpAuthCredentials constructor, the password is never sent across the wire (neither plain-text, nor encrypted). Only user name is sent to the server.

Server-side code

var userAccountRepository = new UserAccountRepository(); // implement this class
var authProvider = new SrpAuthenticationProvider(accounts);
var protocol = new TcpDuplexServerProtocolSetup(8090, provider, true);
var host = new ZyanComponentHost("MyServer", protocol);
host.RegisterComponent<ISampleServer, SampleServer>();

Server-side authentication provider for SRP-6a protocol takes a user account repository instance. It's a custom class used to abstract away the user account storage from the authentication provider. Account repository is a component that implements the following interface:

/// <summary>
/// Account repository for the SRP-6a protocol implementation.
/// </summary>
public interface ISrpAccountRepository
{
	/// <summary>
	/// Finds the user account data by the given username.
	/// </summary>
	/// <param name="userName">Name of the user.</param>
	ISrpAccount FindByName(string userName);
}

/// <summary>
/// SRP-6a account data.
/// </summary>
public interface ISrpAccount
{
	/// <summary>
	/// Gets the name of the user.
	/// </summary>
	string UserName { get; }

	/// <summary>
	/// Gets the salt.
	/// </summary>
	string Salt { get; }

	/// <summary>
	/// Gets the password verifier.
	/// </summary>
	string Verifier { get; }
}

Storing and retrieving the user accounts is up to the application developer. The typical storage for the user accounts is a database table.

Adjustable parameters

This implementation of the SRP-6a protocol has the following adjustable parameters:

Name Description Default value
N Large safe prime 0xAC6BDB41... (2048 bits)
g Generator 2
H Hash function SHA256

The parameters are represented by SrpParameters class. The default constructor produces the default parameters:

var defaultParams = new SrpParameters(); // sha256, 2048-bit safe prime, g=2

To change the parameters, use SrpParameters.Create<T> static method where T is a hashing algorithm type defined in the System.Security.Cryptography namespace:

using System.Security.Cryptography;

var sha512 = SrpParameters.Create<SHA512>();
var sha384 = SrpParameters.Create<SHA384>();

N and g parameters are also adjustable:

var tmp = SrpParameters.Create<MD5>("23", "5"); // not safe, just an example

Using custom SRP parameters

SrpAuthCredentials and SrpAuthenticationProvider classes both accept optional SrpParameters argument. Make sure to use the same parameters on both sides of the wire:

// interfaces
public static class Setup
{
    // sha384, 512-bit prime number (faster, but less safe), g=5
    public static SrpParameters MySrpParameters { get; } = SrpParameters.Create<SHA384>(
        "115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", "05");
}

// server
var authProvider = new SrpAuthenticationProvider(userRepository, Setup.MySrpParameters);

// client
var credentials = new SrpAuthCredentials(userName, password);

Note: saved credentials depend on the SRP parameters used. Adjusting the SRP parameters will require changing all the user's passwords.