A modern SRP-6a implementation for .NET Standard 1.6+ and .NET Framework 3.5+.
Based on and is compatible with secure-remote-password npm package by Linus Unnebäck (see Compatibility).
dotnet add package srp
To create an account, a client provides the following three values:
- Identifier (username or email)
- Salt
- Verifier
The salt and verifier are calculated as follows:
using SecureRemotePassword;
// a user enters his name and password
var userName = "alice";
var password = "password123";
var client = new SrpClient();
var salt = client.GenerateSalt();
var privateKey = client.DerivePrivateKey(salt, userName, password);
var verifier = client.DeriveVerifier(privateKey);
// send userName, salt and verifier to server
Authentication involves several steps:
The client generates an ephemeral secret/public value pair and sends the public value and user name to server:
using SecureRemotePassword;
// a user enters his name
var userName = "alice";
var client = new SrpClient();
var clientEphemeral = client.GenerateEphemeral(verifier);
// send userName and clientEphemeral.Public to server
The server retrieves salt
and verifier
from the database using the
client-provided userName
. Then it generates its own ephemeral secret/public
value pair:
using SecureRemotePassword;
// retrieved from the database
var salt = "beb25379...";
var verifier = "7e273de8...";
var server = new SrpServer();
var serverEphemeral = server.GenerateEphemeral();
// store serverEphemeral.Secret for later use
// send salt and serverEphemeral.Public to the client
The client derives the shared session key and a proof of it to provide to the server:
using SecureRemotePassword;
// a user enters his password
var password = "password123";
var client = new SrpClient();
var privateKey = client.DerivePrivateKey(salt, userName, password);
var clientSession = client.DeriveSession(clientEphemeral.Secret,
serverPublicEphemeral, salt, userName, privateKey);
// send clientSession.Proof to the server
The server derives the shared session key and verifies that the client has the same key using the provided proof value:
using SecureRemotePassword;
// get the serverEphemeral.Secret stored in step 2
var serverSecretEphemeral = "e487cb59...";
var server = new SrpServer();
var serverSession = server.DeriveSession(serverSecretEphemeral,
clientPublicEphemeral, salt, userName, verifier, clientSessionProof);
// send serverSession.Proof to the client
Finally, the client verifies that the server has derived the same session key using the server's proof value:
using SecureRemotePassword;
var client = new SrpClient();
client.VerifySession(clientEphemeral.Public, clientSession, serverSessionProof);
using SecureRemotePassword;
var client = new SrpClient();
var server = new SrpServer();
// sign up
var salt = client.GenerateSalt();
var privateKey = client.DerivePrivateKey(salt, username, password);
var verifier = client.DeriveVerifier(privateKey);
// authenticate
var clientEphemeral = client.GenerateEphemeral();
var serverEphemeral = server.GenerateEphemeral(verifier);
var clientSession = client.DeriveSession(clientEphemeral.Secret, serverEphemeral.Public, salt, username, privateKey);
var serverSession = server.DeriveSession(serverEphemeral.Secret, clientEphemeral.Public, salt, username, verifier, clientSession.Proof);
client.VerifySession(clientEphemeral.Public, clientSession, serverSession.Proof);
// both the client and the server have the same session key
Assert.AreEqual(clientSession.Key, serverSession.Key);
This SRP-6a implementation uses sha256
hash function and 2048-bit group values
by default. Any class derived from HashAlgorithm
can be used as H
.
Customizing the parameters is easy:
using System.Security.Cryptography;
using SecureRemotePassword;
// use predefined 4096-bit group with SHA512 hash function
var customParams = SrpParameters.Create4096<SHA512>();
SrpParameters
has helper methods for all predefined groups from RFC5054:
Create1024<SHA1>()
, etc.
It's also possible to specify custom values of N
and g
:
var N = "D4C7F8A2B32C11B8FBA9581EC4BA...";
var customParams = SrpParameters.Create<SHA1>(N, "02");
Custom SRP parameters are then passed to SrpClient
and SrpServer
constructors.
Make sure to use the same parameters on both sides:
var client = new SrpClient(customParams);
var server = new SrpServer(customParams);
srp.net
is designed to be compatible with other implementations hosted
in secure-remote-password organization.
At the time of writing, the secure-remote-password npm package is incompatible with this implementation because it does not pad values according to RFC5054.
- If you have control over both client and server, it is recommended to upgrade both to this version, as outlined here.
- If you are forced to maintain compatibility with an existing server, you can disable padding by initializing the client with
new SrpClient(new SrpParameters { PaddedLength = 0 })
. This is not recommended, as the resulting behavior is incompatible with libraries that follow the standard.
Other compatible libraries are listed here.
- Secure Remote Password protocol, documentation, wikipedia
- RFC2945 — The SRP Authentication and Key Exchange System
- RFC5054 — Using the Secure Remote Password (SRP) Protocol for TLS Authentication