This repository contains test vectors for validating the SRP-6a protocol implementations.
Test vectors are JSON files specifying the exact values for each authentication step.
Each file contains a set of test vectors for different initialization parameters.
- Load test vectors using a suitable JSON implementation for your platform.
- Initialize your SRP library using
H
,N
,g
andsize
parameters. - Ignore the test vector if your library doesn't support the specified hash function.
- Verify each computation step against the values from the test vector.
H
— hash function: sha1, sha256, sha512, blake2b-256, etc.size
— prime number size (bits)N
— large safe prime numberg
— group generatorI
— user identifier (user name, email, etc)P
— user passwords
— saltk
— multiplier parameterx
— private key, derived from the user name, password and saltv
— verifier, derived from the private keya
— client secret ephemeral valueb
— server secret ephemeral valueA
— client public ephemeral valueB
— server public ephemeral valueu
— u, derived from A and BS
— premaster secret, computed by client and serverK
— shared session key (optional)M1
— client session proof (optional)M2
— server session proof (optional)
Note: K
, M1
and M2
parameters may be missing in the test vector.
RFC5054 document doesn't specify these values. They are calculated as follows:
- K = H(S)
- M1 = H(H(N) xor H(g), H(I), s, A, B, K)
- M2 = H(A, M1, K)
Test vector definition in C#:
public class TestVectorSet
{
public string Comments { get; set; }
public string Url { get; set; }
public TestVector[] TestVectors { get; set; }
}
public class TestVector
{
public string H { get; set; }
public int Size { get; set; }
public string N { get; set; }
public string g { get; set; }
public string I { get; set; }
public string P { get; set; }
public string s { get; set; }
public string k { get; set; }
public string x { get; set; }
public string v { get; set; }
public string a { get; set; }
public string b { get; set; }
public string A { get; set; }
public string B { get; set; }
public string u { get; set; }
public string S { get; set; }
// optional parameters, missing in RFC5054 test vector
public string K { get; set; }
public string M1 { get; set; }
public string M2 { get; set; }
}
Loading test vectors from a file:
using Newtonsoft.Json;
var json = File.ReadAllText("rfc5054.json");
var testVectors = JsonConvert.DeserializeObject<TestVectorSet>(json);
foreach (var tv in testVectors.TestVectors)
{
VerifyTestVector(tv);
}
Verifying a SRP implementation using a test vector:
private void VerifyTestVector(TestVector testVector)
{
// prepare SRP parameters
var parameters = CreateParameters(testVector);
var N = parameters.N;
var g = parameters.G;
var H = parameters.H;
// validate the multiplier parameter
var k = parameters.K;
var kx = SrpInteger.FromHex(testVector.k);
Assert.AreEqual(kx, k);
// prepare user name, password and salt
var I = testVector.I;
var P = testVector.P;
var s = SrpInteger.FromHex(testVector.s).ToHex();
var client = new SrpClient(parameters);
var server = new SrpServer(parameters);
// validate the private key
var x = SrpInteger.FromHex(client.DerivePrivateKey(s, I, P));
var xx = SrpInteger.FromHex(testVector.x);
Assert.AreEqual(xx, x);
// validate the verifier
var v = SrpInteger.FromHex(client.DeriveVerifier(x));
var vx = SrpInteger.FromHex(testVector.v);
Assert.AreEqual(vx, v);
// client ephemeral
var a = SrpInteger.FromHex(testVector.a);
var A = client.ComputeA(a);
var Ax = SrpInteger.FromHex(testVector.A);
Assert.AreEqual(Ax, A);
var clientEphemeral = new SrpEphemeral { Public = A, Secret = a };
// server ephemeral
var b = SrpInteger.FromHex(testVector.b);
var B = server.ComputeB(v, b);
var Bx = SrpInteger.FromHex(testVector.B);
Assert.AreEqual(Bx, B);
var serverEphemeral = new SrpEphemeral { Public = B, Secret = a };
// validate u
var u = client.ComputeU(A, B);
var ux = SrpInteger.FromHex(testVector.u);
Assert.AreEqual(ux, u);
// premaster secret — client version
var S = client.ComputeS(a, B, u, x);
var Sx = SrpInteger.FromHex(testVector.S);
Assert.AreEqual(Sx, S);
// premaster secret — server version
S = server.ComputeS(A, b, u, v);
Assert.AreEqual(Sx, S);
// client session
var clientSession = client.DeriveSession(a, B, s, I, x);
if (testVector.M1 != null)
{
Assert.AreEqual(testVector.M1, clientSession.Proof);
}
// server session
var serverSession = server.DeriveSession(b, A, s, I, v, clientSession.Proof);
Assert.AreEqual(clientSession.Key, serverSession.Key);
if (testVector.M2 != null)
{
Assert.AreEqual(testVector.M2, serverSession.Proof);
}
// verify server session
client.VerifySession(A, clientSession, serverSession.Proof);
if (testVector.K != null)
{
Assert.AreEqual(testVector.K, serverSession.Key);
}
}