/// <summary> /// Verifies the session using the server-provided session proof. /// </summary> /// <param name="clientPublicEphemeral">The client public ephemeral.</param> /// <param name="clientSession">The client session.</param> /// <param name="serverSessionProof">The server session proof.</param> public void VerifySession(string clientPublicEphemeral, SrpSession clientSession, string serverSessionProof) { // H — One-way hash function var H = Parameters.Hash; // A — Public ephemeral values // M — Proof of K // K — Shared, strong session key var A = SrpInteger.FromHex(clientPublicEphemeral); var M = SrpInteger.FromHex(clientSession.Proof); var K = SrpInteger.FromHex(clientSession.Key); // H(A, M, K) var expected = H(A, M, K); var actual = SrpInteger.FromHex(serverSessionProof); if (actual != expected) { // fixme: .code, .statusCode, etc. throw new SecurityException("Server provided session proof is invalid"); } }
/// <summary> /// Generates the random salt of the same size as a used hash. /// </summary> public string GenerateSalt() { var hashSize = Parameters.HashSizeBytes; return(SrpInteger.RandomInteger(hashSize).ToHex()); }
/// <summary> /// Derives the server session. /// </summary> /// <param name="serverSecretEphemeral">The server secret ephemeral.</param> /// <param name="clientPublicEphemeral">The client public ephemeral.</param> /// <param name="salt">The salt.</param> /// <param name="username">The username.</param> /// <param name="verifier">The verifier.</param> /// <param name="clientSessionProof">The client session proof value.</param> /// <returns>Session key and proof.</returns> public SrpSession DeriveSession(string serverSecretEphemeral, string clientPublicEphemeral, string salt, string username, string verifier, string clientSessionProof) { // N — A large safe prime (N = 2q+1, where q is prime) // g — A generator modulo N // k — Multiplier parameter (k = H(N, g) in SRP-6a, k = 3 for legacy SRP-6) // H — One-way hash function // PAD — Pad the number to have the same number of bytes as N var N = Parameters.Prime; var g = Parameters.Generator; var k = Parameters.Multiplier; var H = Parameters.Hash; var PAD = Parameters.Pad; // b — Secret ephemeral values // A — Public ephemeral values // s — User's salt // p — Cleartext Password // I — Username // v — Password verifier var b = SrpInteger.FromHex(serverSecretEphemeral); var A = SrpInteger.FromHex(clientPublicEphemeral); var s = SrpInteger.FromHex(salt); var I = username + string.Empty; var v = SrpInteger.FromHex(verifier); // B = kv + g^b (b = random number) var B = ((k * v) + g.ModPow(b, N)) % N; // A % N > 0 if (A % N == 0) { // fixme: .code, .statusCode, etc. throw new SecurityException("The client sent an invalid public ephemeral"); } // u = H(PAD(A), PAD(B)) var u = H(PAD(A), PAD(B)); // S = (Av^u) ^ b (computes session key) var S = ComputeS(A, b, u, v); // K = H(S) var K = H(S); // M = H(H(N) xor H(g), H(I), s, A, B, K) var M = H(H(N) ^ H(g), H(I), s, A, B, K); // validate client session proof var expected = M; var actual = SrpInteger.FromHex(clientSessionProof); if (actual != expected) { // fixme: .code, .statusCode, etc. throw new SecurityException("Client provided session proof is invalid"); } // P = H(A, M, K) var P = H(A, M, K); return(new SrpSession { Key = K.ToHex(), Proof = P.ToHex(), }); }