/// <summary> /// Computes the server evidence from the given parameters. /// </summary> /// <param name="clientPublicKey">The client's ephemeral public key.</param> /// <param name="clientProof"></param> /// <param name="sharedKey">The shared context key.</param> /// <param name="authId">The authorization identity.</param> /// <param name="options">The raw options string as sent by the /// client.</param> /// <param name="sid">The session id sent by the server.</param> /// <param name="ttl">The time-to-live value for the session id sent /// by the server.</param> /// <param name="hashAlgorithm">The message digest algorithm to use for /// calculating the server proof.</param> /// <returns>The server proof as an array of bytes.</returns> public static byte[] ComputeServerProof(Mpi clientPublicKey, byte[] clientProof, Mpi sharedKey, string authId, string options, string sid, uint ttl, HashAlgorithm hashAlgorithm) { byte[] A = clientPublicKey.ToBytes(), M1 = clientProof, K = sharedKey.ToBytes(), I = Encoding.UTF8.GetBytes(authId), o = Encoding.UTF8.GetBytes(options), _sid = Encoding.UTF8.GetBytes(sid); HashAlgorithm H = hashAlgorithm; // The proof is calculated as follows: // // H( bytes(A) // | bytes(M1) // | bytes(K) // | bytes(H( bytes(I) )) // | bytes(H( bytes(o) )) // | bytes(sid) // | ttl // ) byte[] seq = new ByteBuilder() .Append(A) .Append(M1) .Append(K) .Append(H.ComputeHash(I)) .Append(H.ComputeHash(o)) .Append(_sid) .Append(ttl, true) .ToArray(); return(H.ComputeHash(seq)); }
/// <summary> /// Computes the client evidence from the given parameters. /// </summary> /// <param name="safePrimeModulus">The safe prime modulus sent by the /// server.</param> /// <param name="generator">The generator sent by the server.</param> /// <param name="username">The username to authenticate with.</param> /// <param name="salt">The client's password salt.</param> /// <param name="clientPublicKey">The client's ephemeral public key.</param> /// <param name="serverPublicKey">The server's ephemeral public key.</param> /// <param name="sharedKey">The shared context key.</param> /// <param name="authId">The authorization identity.</param> /// <param name="options">The raw options string as received from the /// server.</param> /// <param name="hashAlgorithm">The message digest algorithm to use for /// calculating the client proof.</param> /// <returns>The client proof as an array of bytes.</returns> public static byte[] ComputeClientProof(Mpi safePrimeModulus, Mpi generator, string username, byte[] salt, Mpi clientPublicKey, Mpi serverPublicKey, Mpi sharedKey, string authId, string options, HashAlgorithm hashAlgorithm) { byte[] N = safePrimeModulus.ToBytes(), g = generator.ToBytes(), U = Encoding.UTF8.GetBytes(username), s = salt, A = clientPublicKey.ToBytes(), B = serverPublicKey.ToBytes(), K = sharedKey.ToBytes(), I = Encoding.UTF8.GetBytes(authId), L = Encoding.UTF8.GetBytes(options); HashAlgorithm H = hashAlgorithm; // The proof is calculated as follows: // // H( bytes(H( bytes(N) )) ^ bytes( H( bytes(g) )) // | bytes(H( bytes(U) )) // | bytes(s) // | bytes(A) // | bytes(B) // | bytes(K) // | bytes(H( bytes(I) )) // | bytes(H( bytes(L) )) // ) byte[] seq = new ByteBuilder() .Append(Xor(H.ComputeHash(N), H.ComputeHash(g))) .Append(H.ComputeHash(U)) .Append(s) .Append(A) .Append(B) .Append(K) .Append(H.ComputeHash(I)) .Append(H.ComputeHash(L)) .ToArray(); return(H.ComputeHash(seq)); }
/// <summary> /// Calculates the shared context key K from the given parameters. /// </summary> /// <param name="salt">The user's password salt.</param> /// <param name="username">The username to authenticate with.</param> /// <param name="password">The password to authenticate with.</param> /// <param name="clientPublicKey">The client's ephemeral public key.</param> /// <param name="serverPublicKey">The server's ephemeral public key.</param> /// <param name="clientPrivateKey">The client's private key.</param> /// <param name="generator">The generator sent by the server.</param> /// <param name="safePrimeModulus">The safe prime modulus sent by the /// server.</param> /// <param name="hashAlgorithm">The negotiated hash algorithm to use /// for the calculations.</param> /// <returns>The shared context key K as a "multi-precision /// integer".</returns> /// <remarks> /// A = Client Public Key /// B = Server Public Key /// N = Safe Prime Modulus /// U = Username /// p = Password /// s = User's Password Salt /// a = Client Private Key /// g = Generator /// K = Shared Public Key /// </remarks> public static Mpi ComputeSharedKey(byte[] salt, string username, string password, Mpi clientPublicKey, Mpi serverPublicKey, Mpi clientPrivateKey, Mpi generator, Mpi safePrimeModulus, HashAlgorithm hashAlgorithm) { // u = H(A | B) byte[] u = hashAlgorithm.ComputeHash(new ByteBuilder() .Append(clientPublicKey.ToBytes()) .Append(serverPublicKey.ToBytes()) .ToArray()); // x = H(s | H(U | ":" | p)) byte[] up = hashAlgorithm.ComputeHash( Encoding.UTF8.GetBytes(username + ":" + password)), sup = new ByteBuilder().Append(salt).Append(up).ToArray(), x = hashAlgorithm.ComputeHash(sup); // S = ((B - (3 * g ^ x)) ^ (a + u * x)) % N Mpi _u = new Mpi(u), _x = new Mpi(x); ts.TraceInformation("ComputeSharedKey: _u = " + _u.Value.ToString("X")); ts.TraceInformation("ComputeSharedKey: _x = " + _x.Value.ToString("X")); // base = B - (3 * (g ^ x)) BigInteger _base = BigInteger.Subtract(serverPublicKey.Value, BigInteger.Multiply(new BigInteger(3), BigInteger.ModPow(generator.Value, _x.Value, safePrimeModulus.Value)) % safePrimeModulus.Value); if (_base.Sign < 0) { _base = BigInteger.Add(_base, safePrimeModulus.Value); } ts.TraceInformation("ComputeSharedKey: _base = " + _base.ToString("X")); // Alternative way to calculate base; This is not being used in actual calculations // but still here to ease debugging. BigInteger gx = BigInteger.ModPow(generator.Value, _x.Value, safePrimeModulus.Value), gx3 = BigInteger.Multiply(new BigInteger(3), gx) % safePrimeModulus.Value; ts.TraceInformation("ComputeSharedKey: gx = " + gx.ToString("X")); BigInteger @base = BigInteger.Subtract(serverPublicKey.Value, gx3) % safePrimeModulus.Value; if (@base.Sign < 0) { @base = BigInteger.Add(@base, safePrimeModulus.Value); } ts.TraceInformation("ComputeSharedKey: @base = " + @base.ToString("X")); // exp = a + u * x BigInteger exp = BigInteger.Add(clientPrivateKey.Value, BigInteger.Multiply(_u.Value, _x.Value)), S = BigInteger.ModPow(_base, exp, safePrimeModulus.Value); ts.TraceInformation("ComputeSharedKey: exp = " + exp.ToString("X")); ts.TraceInformation("ComputeSharedKey: S = " + S.ToString("X")); // K = H(S) return(new Mpi(hashAlgorithm.ComputeHash(new Mpi(S).ToBytes()))); }
/// <summary> /// Computes the server evidence from the given parameters. /// </summary> /// <param name="clientPublicKey">The client's ephemeral public key.</param> /// <param name="clientProof"></param> /// <param name="sharedKey">The shared context key.</param> /// <param name="authId">The authorization identity.</param> /// <param name="options">The raw options string as sent by the /// client.</param> /// <param name="sid">The session id sent by the server.</param> /// <param name="ttl">The time-to-live value for the session id sent /// by the server.</param> /// <param name="hashAlgorithm">The message digest algorithm to use for /// calculating the server proof.</param> /// <returns>The server proof as an array of bytes.</returns> public static byte[] ComputeServerProof(Mpi clientPublicKey, byte[] clientProof, Mpi sharedKey, string authId, string options, string sid, uint ttl, HashAlgorithm hashAlgorithm) { byte[] A = clientPublicKey.ToBytes(), M1 = clientProof, K = sharedKey.ToBytes(), I = Encoding.UTF8.GetBytes(authId), o = Encoding.UTF8.GetBytes(options), _sid = Encoding.UTF8.GetBytes(sid); HashAlgorithm H = hashAlgorithm; // The proof is calculated as follows: // // H( bytes(A) // | bytes(M1) // | bytes(K) // | bytes(H( bytes(I) )) // | bytes(H( bytes(o) )) // | bytes(sid) // | ttl // ) byte[] seq = new ByteBuilder() .Append(A) .Append(M1) .Append(K) .Append(H.ComputeHash(I)) .Append(H.ComputeHash(o)) .Append(_sid) .Append(ttl, true) .ToArray(); return H.ComputeHash(seq); }
/// <summary> /// Computes the client evidence from the given parameters. /// </summary> /// <param name="safePrimeModulus">The safe prime modulus sent by the /// server.</param> /// <param name="generator">The generator sent by the server.</param> /// <param name="username">The username to authenticate with.</param> /// <param name="salt">The client's password salt.</param> /// <param name="clientPublicKey">The client's ephemeral public key.</param> /// <param name="serverPublicKey">The server's ephemeral public key.</param> /// <param name="sharedKey">The shared context key.</param> /// <param name="authId">The authorization identity.</param> /// <param name="options">The raw options string as received from the /// server.</param> /// <param name="hashAlgorithm">The message digest algorithm to use for /// calculating the client proof.</param> /// <returns>The client proof as an array of bytes.</returns> public static byte[] ComputeClientProof(Mpi safePrimeModulus, Mpi generator, string username, byte[] salt, Mpi clientPublicKey, Mpi serverPublicKey, Mpi sharedKey, string authId, string options, HashAlgorithm hashAlgorithm) { byte[] N = safePrimeModulus.ToBytes(), g = generator.ToBytes(), U = Encoding.UTF8.GetBytes(username), s = salt, A = clientPublicKey.ToBytes(), B = serverPublicKey.ToBytes(), K = sharedKey.ToBytes(), I = Encoding.UTF8.GetBytes(authId), L = Encoding.UTF8.GetBytes(options); HashAlgorithm H = hashAlgorithm; // The proof is calculated as follows: // // H( bytes(H( bytes(N) )) ^ bytes( H( bytes(g) )) // | bytes(H( bytes(U) )) // | bytes(s) // | bytes(A) // | bytes(B) // | bytes(K) // | bytes(H( bytes(I) )) // | bytes(H( bytes(L) )) // ) byte[] seq = new ByteBuilder() .Append(Xor(H.ComputeHash(N), H.ComputeHash(g))) .Append(H.ComputeHash(U)) .Append(s) .Append(A) .Append(B) .Append(K) .Append(H.ComputeHash(I)) .Append(H.ComputeHash(L)) .ToArray(); return H.ComputeHash(seq); }
/// <summary> /// Calculates the shared context key K from the given parameters. /// </summary> /// <param name="salt">The user's password salt.</param> /// <param name="username">The username to authenticate with.</param> /// <param name="password">The password to authenticate with.</param> /// <param name="clientPublicKey">The client's ephemeral public key.</param> /// <param name="serverPublicKey">The server's ephemeral public key.</param> /// <param name="clientPrivateKey">The client's private key.</param> /// <param name="generator">The generator sent by the server.</param> /// <param name="safePrimeModulus">The safe prime modulus sent by the /// server.</param> /// <param name="hashAlgorithm">The negotiated hash algorithm to use /// for the calculations.</param> /// <returns>The shared context key K as a "multi-precision /// integer".</returns> /// <remarks> /// A = Client Public Key /// B = Server Public Key /// N = Safe Prime Modulus /// U = Username /// p = Password /// s = User's Password Salt /// a = Client Private Key /// g = Generator /// K = Shared Public Key /// </remarks> public static Mpi ComputeSharedKey(byte[] salt, string username, string password, Mpi clientPublicKey, Mpi serverPublicKey, Mpi clientPrivateKey, Mpi generator, Mpi safePrimeModulus, HashAlgorithm hashAlgorithm) { // u = H(A | B) byte[] u = hashAlgorithm.ComputeHash(new ByteBuilder() .Append(clientPublicKey.ToBytes()) .Append(serverPublicKey.ToBytes()) .ToArray()); // x = H(s | H(U | ":" | p)) byte[] up = hashAlgorithm.ComputeHash( Encoding.UTF8.GetBytes(username + ":" + password)), sup = new ByteBuilder().Append(salt).Append(up).ToArray(), x = hashAlgorithm.ComputeHash(sup); // S = ((B - (3 * g ^ x)) ^ (a + u * x)) % N Mpi _u = new Mpi(u), _x = new Mpi(x); ts.TraceInformation("ComputeSharedKey: _u = " + _u.Value.ToString("X")); ts.TraceInformation("ComputeSharedKey: _x = " + _x.Value.ToString("X")); // base = B - (3 * (g ^ x)) BigInteger _base = BigInteger.Subtract(serverPublicKey.Value, BigInteger.Multiply(new BigInteger(3), BigInteger.ModPow(generator.Value, _x.Value, safePrimeModulus.Value)) % safePrimeModulus.Value); if (_base.Sign < 0) _base = BigInteger.Add(_base, safePrimeModulus.Value); ts.TraceInformation("ComputeSharedKey: _base = " + _base.ToString("X")); // Alternative way to calculate base; This is not being used in actual calculations // but still here to ease debugging. BigInteger gx = BigInteger.ModPow(generator.Value, _x.Value, safePrimeModulus.Value), gx3 = BigInteger.Multiply(new BigInteger(3), gx) % safePrimeModulus.Value; ts.TraceInformation("ComputeSharedKey: gx = " + gx.ToString("X")); BigInteger @base = BigInteger.Subtract(serverPublicKey.Value, gx3) % safePrimeModulus.Value; if (@base.Sign < 0) @base = BigInteger.Add(@base, safePrimeModulus.Value); ts.TraceInformation("ComputeSharedKey: @base = " + @base.ToString("X")); // exp = a + u * x BigInteger exp = BigInteger.Add(clientPrivateKey.Value, BigInteger.Multiply(_u.Value, _x.Value)), S = BigInteger.ModPow(_base, exp, safePrimeModulus.Value); ts.TraceInformation("ComputeSharedKey: exp = " + exp.ToString("X")); ts.TraceInformation("ComputeSharedKey: S = " + S.ToString("X")); // K = H(S) return new Mpi(hashAlgorithm.ComputeHash(new Mpi(S).ToBytes())); }