Beispiel #1
0
        /// <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));
        }
Beispiel #2
0
        /// <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));
        }
Beispiel #3
0
        /// <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())));
        }