Exemplo n.º 1
0
		/// <summary>
		/// Creates and initializes a new instance of the ClientMessage2 class using
		/// the specified public key and client proof.
		/// </summary>
		/// <param name="publicKey">The client's public key.</param>
		/// <param name="proof">The calculated client proof.</param>
		/// <exception cref="ArgumentNullException">Thrown if either the public key
		/// or the proof parameter is null.</exception>
		public ClientMessage2(Mpi publicKey, byte[] proof)
			: this() {
			publicKey.ThrowIfNull("publicKey");
			proof.ThrowIfNull("proof");

			PublicKey = publicKey;
			Proof = proof;
		}
Exemplo n.º 2
0
		/// <summary>
		/// Calculates the client's ephemeral public key.
		/// </summary>
		/// <param name="generator">The generator sent by the server.</param>
		/// <param name="safePrimeModulus">The safe prime modulus sent by
		/// the server.</param>
		/// <param name="privateKey">The client's private key.</param>
		/// <returns>The client's ephemeral public key as a
		/// "multi-precision integer".</returns>
		/// <remarks>
		/// A = Client Public Key
		/// g = Generator
		/// a = Client Private Key
		/// N = Safe Prime Modulus
		/// </remarks>
		public static Mpi ComputeClientPublicKey(Mpi generator, Mpi safePrimeModulus,
			Mpi privateKey) {
			// A = g ^ a % N
			BigInteger result = BigInteger.ModPow(generator.Value, privateKey.Value,
				safePrimeModulus.Value);

			return new Mpi(result);
		}
Exemplo n.º 3
0
		/// <summary>
		/// Determines whether the specified modulus is valid.
		/// </summary>
		/// <param name="N">The modulus to validate.</param>
		/// <returns>True if the specified modulus is valid, otherwise
		/// false.</returns>
		public static bool IsValidModulus(Mpi N) {
			foreach (string s in moduli) {
				BigInteger a = BigInteger.Parse(s, NumberStyles.HexNumber);
				if (BigInteger.Compare(a, N.Value) == 0)
					return true;
			}
			// Fixme: Perform proper validation?
			return false;
		}
Exemplo n.º 4
0
 /// <summary>
 /// Determines whether the specified modulus is valid.
 /// </summary>
 /// <param name="N">The modulus to validate.</param>
 /// <returns>True if the specified modulus is valid, otherwise
 /// false.</returns>
 public static bool IsValidModulus(Mpi N)
 {
     foreach (string s in moduli)
     {
         BigInteger a = BigInteger.Parse(s, NumberStyles.HexNumber);
         if (BigInteger.Compare(a, N.Value) == 0)
         {
             return(true);
         }
     }
     // Fixme: Perform proper validation?
     return(false);
 }
Exemplo n.º 5
0
		public void SerializeClientSecondMessage() {
			BigInteger key = BigInteger.Parse(clientPublicKey,
				NumberStyles.HexNumber);
			Mpi _publicKey = new Mpi(key);

			ClientMessage2 m = new ClientMessage2(_publicKey, clientProof);
			m.InitialVector = clientInitialVector;
			foreach (KeyValuePair<string, string> p in clientOptions)
				m.Options.Add(p.Key, p.Value);

			byte[] serialized = m.Serialize();
			Assert.IsTrue(serialized.SequenceEqual(expectedClientMessage2));

		}
Exemplo n.º 6
0
		/// <summary>
		/// Determines whether the specified generator is valid.
		/// </summary>
		/// <param name="g">The generator to validate.</param>
		/// <returns>True if the specified generator is valid, otherwise
		/// false.</returns>
		public static bool IsValidGenerator(Mpi g) {
			return BigInteger.Compare(new BigInteger(2), g.Value) == 0;
		}
Exemplo n.º 7
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);
		}
Exemplo n.º 8
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);
		}
Exemplo n.º 9
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()));
		}
Exemplo n.º 10
0
 /// <summary>
 /// Determines whether the specified generator is valid.
 /// </summary>
 /// <param name="g">The generator to validate.</param>
 /// <returns>True if the specified generator is valid, otherwise
 /// false.</returns>
 public static bool IsValidGenerator(Mpi g)
 {
     return(BigInteger.Compare(new BigInteger(2), g.Value) == 0);
 }
Exemplo n.º 11
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));
        }
Exemplo n.º 12
0
		/// <summary>
		/// Computes the client response containing the client's public key and
		/// evidence.
		/// </summary>
		/// <param name="challenge">The challenge containing the protocol elements
		/// received from the server in response to the initial client
		/// response.</param>
		/// <returns>An array of bytes containing the client's challenge
		/// response.</returns>
		/// <exception cref="SaslException">Thrown if the server specified any
		/// mandatory options which are not supported.</exception>
		private byte[] ComputeFinalResponse(byte[] challenge) {
			ServerMessage1 m = ServerMessage1.Deserialize(challenge);
			// We don't support integrity protection or confidentiality.
			if (!String.IsNullOrEmpty(m.Options["mandatory"]))
				throw new SaslException("Mandatory options are not supported.");
			// Set up the message digest algorithm.
			var mda = SelectHashAlgorithm(m.Options["mda"]);
			HashAlgorithm = Activator.CreateInstance(mda.Item2) as HashAlgorithm;

			// Compute public and private key.
			PublicKey = Helper.ComputeClientPublicKey(m.Generator,
				m.SafePrimeModulus, PrivateKey);
			// Compute the shared key and client evidence.
			SharedKey = Helper.ComputeSharedKey(m.Salt, Username, Password,
				PublicKey, m.PublicKey, PrivateKey, m.Generator, m.SafePrimeModulus,
				HashAlgorithm);
			ClientProof = Helper.ComputeClientProof(m.SafePrimeModulus,
				m.Generator, Username, m.Salt, PublicKey, m.PublicKey, SharedKey,
				AuthId, m.RawOptions, HashAlgorithm);

			ClientMessage2 response = new ClientMessage2(PublicKey, ClientProof);
			// Let the server know which hash algorithm we are using.
			response.Options["mda"] = mda.Item1;
			// Remember the raw options string because we'll need it again
			// when verifying the server signature.
			Options = response.BuildOptionsString();

			return response.Serialize();
		}
Exemplo n.º 13
0
		/// <summary>
		/// Internal constructor used for unit testing.
		/// </summary>
		/// <param name="username">The username to authenticate with.</param>
		/// <param name="password">The plaintext password to authenticate
		/// with.</param>
		/// <param name="privateKey">The client private key to use.</param>
		/// <exception cref="ArgumentNullException">Thrown if the username
		/// or the password parameter is null.</exception>
		/// <exception cref="ArgumentException">Thrown if the username
		/// parameter is empty.</exception>
		internal SaslSrp(string username, string password, byte[] privateKey)
			: this(username, password) {
				PrivateKey = new Mpi(privateKey);
		}