In the asp.net core PasswordHasher type there is is remark on the VerifyHashedPassword method
/// <remarks>Implementations of this method should be time consistent.</remarks>
And then to compare the hashes it uses code that is deliberately not optimised and written not do early exits in the loop.
// Compares two byte arrays for equality. The method is specifically written so that the loop is not optimized.
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private static bool ByteArraysEqual(byte[] a, byte[] b)
{
if (a == null && b == null)
{
return true;
}
if (a == null || b == null || a.Length != b.Length)
{
return false;
}
var areSame = true;
for (var i = 0; i < a.Length; i++)
{
areSame &= (a[i] == b[i]);
}
return areSame;
}
At first I thought that without this timing could be used to determine how close the hash was, if it takes longer then more of the hash is the same.
However this doesn't make sense because the hash has gone through 1000 iterations of SHA256 at this point. So any change in the password would produce a completely different hash, and knowing that your password produces almost the correct hash does not help you find the correct one.
What is the purpose of ensuring a constant time hash verification?
byte[]
. Just because the code you write isn't used for something right now doesn't mean it won't be misused later! – Carl Walsh May 09 '19 at 23:35varName |= a[i] ^ b[i];
in the loop instead. Initialize the variable to zero. Finally, returnvarName == 0
. The XOR of two values is zero if and only if the values are the same. Once you OR a non-zero value intovarName
, the set bits of the value|=
'd intovarName
will stay set. Bitwise operations on values of the native machine word size are constant time, so the modified function will be constant time too. (Assuming the compiler doesn't, as an optimization, insert an early exit into the loop.) – Future Security May 10 '19 at 15:40