-
Notifications
You must be signed in to change notification settings - Fork 33
Using SRP 6a protocol
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 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
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.
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.
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
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.