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