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); } }