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:
usingSecureRemotePassword;// a user enters his name and passwordvaruserName="alice";varpassword="password123";varclient=newSrpClient();varsalt=client.GenerateSalt();varprivateKey=client.DerivePrivateKey(salt,userName,password);varverifier=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:
usingSecureRemotePassword;// a user enters his namevaruserName="alice";varclient=newSrpClient();varclientEphemeral=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:
usingSecureRemotePassword;// retrieved from the databasevarsalt="beb25379...";varverifier="7e273de8...";varserver=newSrpServer();varserverEphemeral=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:
usingSecureRemotePassword;// a user enters his passwordvarpassword="password123";varclient=newSrpClient();varprivateKey=client.DerivePrivateKey(salt,userName,password);varclientSession=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:
usingSecureRemotePassword;// get the serverEphemeral.Secret stored in step 2varserverSecretEphemeral="e487cb59...";varserver=newSrpServer();varserverSession=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:
usingSecureRemotePassword;varclient=newSrpClient();client.VerifySession(clientEphemeral.Public,clientSession,serverSessionProof);
usingSecureRemotePassword;varclient=newSrpClient();varserver=newSrpServer();// sign upvarsalt=client.GenerateSalt();varprivateKey=client.DerivePrivateKey(salt,username,password);varverifier=client.DeriveVerifier(privateKey);// authenticatevarclientEphemeral=client.GenerateEphemeral();varserverEphemeral=server.GenerateEphemeral(verifier);varclientSession=client.DeriveSession(clientEphemeral.Secret,serverEphemeral.Public,salt,username,privateKey);varserverSession=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 keyAssert.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:
usingSystem.Security.Cryptography;usingSecureRemotePassword;// use predefined 4096-bit group with SHA512 hash functionvarcustomParams=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
:
varN="D4C7F8A2B32C11B8FBA9581EC4BA...";varcustomParams=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:
varclient=newSrpClient(customParams);varserver=newSrpServer(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