public bool AuthenticateAsClient(Stream stream, byte[] additionalChallenge = null)
        {
            if (additionalChallenge == null)
            {
                additionalChallenge = new byte[] { }
            }
            ;

            byte[] clientNonce = m_nonce.Next();
            stream.WriteWithLength(m_usernameBytes);
            stream.WriteWithLength(clientNonce);
            stream.Flush();

            HashMethod hashMethod = (HashMethod)stream.ReadByte();

            byte[] serverNonce = stream.ReadBytes();
            byte[] salt        = stream.ReadBytes();
            int    iterations  = stream.ReadInt32();

            SetServerValues(hashMethod, salt, iterations);

            byte[] authMessage     = Scram.ComputeAuthMessage(serverNonce, clientNonce, salt, m_usernameBytes, iterations, additionalChallenge);
            byte[] clientSignature = ComputeClientSignature(authMessage);
            byte[] clientProof     = Scram.XOR(m_clientKey, clientSignature);
            stream.WriteWithLength(clientProof);
            stream.Flush();

            byte[] serverSignature       = ComputeServerSignature(authMessage);
            byte[] serverSignatureVerify = stream.ReadBytes();
            return(serverSignature.SecureEquals(serverSignatureVerify));
        }
    }
        /// <summary>
        /// Requests that the provided stream be authenticated
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="additionalChallenge">Additional data to include in the challenge. If using SSL certificates,
        /// adding the thumbprint to the challenge will allow detecting man in the middle attacks.</param>
        /// <returns></returns>
        public ScramServerSession AuthenticateAsServer(Stream stream, byte[] additionalChallenge = null)
        {
            if (additionalChallenge == null)
            {
                additionalChallenge = new byte[] { }
            }
            ;

            byte[] usernameBytes = stream.ReadBytes();
            byte[] clientNonce   = stream.ReadBytes();

            ScramUserCredential user;

            if (!Users.TryLookup(usernameBytes, out user))
            {
                return(null);
            }

            byte[] serverNonce = m_nonce.Next();
            stream.WriteByte((byte)user.HashMethod);
            stream.WriteWithLength(serverNonce);
            stream.WriteWithLength(user.Salt);
            stream.Write(user.Iterations);
            stream.Flush();

            byte[] authMessage     = Scram.ComputeAuthMessage(serverNonce, clientNonce, user.Salt, usernameBytes, user.Iterations, additionalChallenge);
            byte[] clientSignature = user.ComputeClientSignature(authMessage);
            byte[] serverSignature = user.ComputeServerSignature(authMessage);
            byte[] clientProof     = stream.ReadBytes();

            byte[] clientKeyVerify = Scram.XOR(clientProof, clientSignature);
            byte[] storedKeyVerify = user.ComputeStoredKey(clientKeyVerify);

            if (storedKeyVerify.SecureEquals(user.StoredKey))
            {
                //Client holds the password
                //Send ServerSignature
                stream.WriteWithLength(serverSignature);
                stream.Flush();
                return(new ScramServerSession(user.UserName));
            }
            return(null);
        }
    }
Exemple #3
0
 public byte[] ComputeClientSignature(byte[] authMessage)
 {
     byte[] result = new byte[m_clientSignature.GetMacSize()];
     if (Monitor.TryEnter(m_clientSignature))
     {
         try
         {
             m_clientSignature.BlockUpdate(authMessage, 0, authMessage.Length);
             m_clientSignature.DoFinal(result, 0);
         }
         finally
         {
             Monitor.Exit(m_clientSignature);
         }
     }
     else
     {
         return(HMAC.Compute(Scram.CreateDigest(HashMethod), StoredKey, authMessage));
     }
     return(result);
 }
Exemple #4
0
 public byte[] ComputeStoredKey(byte[] clientKey)
 {
     byte[] result = new byte[m_computeStoredKey.GetDigestSize()];
     if (Monitor.TryEnter(m_computeStoredKey))
     {
         try
         {
             m_computeStoredKey.BlockUpdate(clientKey, 0, clientKey.Length);
             m_computeStoredKey.DoFinal(result, 0);
             return(result);
         }
         finally
         {
             Monitor.Exit(m_computeStoredKey);
         }
     }
     else
     {
         return(Hash.Compute(Scram.CreateDigest(HashMethod), clientKey));
     }
 }
Exemple #5
0
        /// <summary>
        /// Adds the following user information to the server's user database
        /// </summary>
        /// <param name="username">the username. Cannot be more than 100 characters</param>
        /// <param name="password">the password. Cannot be more than 1024 characters</param>
        /// <param name="iterations">The number of iterations. On 2014 technology, 2000 iterations takes about 10ms to compute</param>
        /// <param name="saltSize">The size of the salt. Defaults to 32 bytes.</param>
        /// <param name="hashMethod">The hash method to use for authentication</param>
        /// <remarks>
        /// Setting a vary large Iterations will not effect how long it takes to negotiate a client on the server end. This is because
        /// the server precomputes the hash results. The client can optionally also precomute the results so negotiation can take
        /// milliseconds.
        /// </remarks>
        public ScramUserCredential(string username, string password, int iterations = 4000, int saltSize = 32, HashMethod hashMethod = HashMethod.Sha256)
        {
            UserName  = username.Normalize(NormalizationForm.FormKC);
            UserBytes = new ReadonlyByteArray(Encoding.UTF8.GetBytes(UserName));

            Iterations = iterations;
            HashMethod = hashMethod;
            Salt       = SaltGenerator.Create(saltSize);

            byte[] saltedPassword = Scram.GenerateSaltedPassword(password.Normalize(NormalizationForm.FormKC), Salt, Iterations);
            byte[] clientKey      = Scram.ComputeClientKey(hashMethod, saltedPassword);

            StoredKey = Scram.ComputeStoredKey(hashMethod, clientKey);
            ServerKey = Scram.ComputeServerKey(hashMethod, saltedPassword);

            m_clientSignature = new HMac(Scram.CreateDigest(HashMethod));
            m_clientSignature.Init(new KeyParameter(StoredKey));

            m_serverSignature = new HMac(Scram.CreateDigest(HashMethod));
            m_serverSignature.Init(new KeyParameter(ServerKey));

            m_computeStoredKey = Scram.CreateDigest(HashMethod);
        }
        /// <summary>
        /// Sets the server parameters and regenerates the salted password if
        /// the salt values have changed.
        /// </summary>
        /// <param name="hashMethod">the hashing method</param>
        /// <param name="salt">the salt for the user credentials.</param>
        /// <param name="iterations">the number of iterations.</param>
        void SetServerValues(HashMethod hashMethod, byte[] salt, int iterations)
        {
            bool hasPasswordDataChanged = false;
            bool hasHashMethodChanged   = false;

            if (m_salt == null || !salt.SecureEquals(m_salt))
            {
                hasPasswordDataChanged = true;
                m_salt = salt;
            }
            if (iterations != m_iterations)
            {
                hasPasswordDataChanged = true;
                m_iterations           = iterations;
            }
            if (m_hashMethod != hashMethod)
            {
                m_hashMethod         = hashMethod;
                hasHashMethodChanged = true;
            }

            if (hasPasswordDataChanged)
            {
                m_saltedPassword = Scram.GenerateSaltedPassword(m_passwordBytes, m_salt, m_iterations);
            }
            if (hasPasswordDataChanged || hasHashMethodChanged)
            {
                m_serverKey       = Scram.ComputeServerKey(m_hashMethod, m_saltedPassword);
                m_clientKey       = Scram.ComputeClientKey(m_hashMethod, m_saltedPassword);
                m_storedKey       = Scram.ComputeStoredKey(m_hashMethod, m_clientKey);
                m_clientSignature = new HMac(Scram.CreateDigest(m_hashMethod));
                m_clientSignature.Init(new KeyParameter(m_storedKey));

                m_serverSignature = new HMac(Scram.CreateDigest(m_hashMethod));
                m_serverSignature.Init(new KeyParameter(m_serverKey));
            }
        }