Explanation is in the function. Please point out any egregious errors:
create function api.ConstantTimeCompare (
@x varbinary(8000) = 0x00
, @y varbinary(8000) = 0x00
)
/*
What? Compares two variable length binary strings byte by byte in constant time.
When? Cryptography.
Why? Given the strings 0x1234 and 0x1213 a simple equality comparison will stop processing after
it hits the first mismatch at byte position 3. An opponent who only knows @x can exploit this
feature to guess @y by trying thousands of comparisons and gathering statistics on how long
each one took.
In other words, assuming that it takes 100 milliseconds to compare at 16 byte string an
opponent can rely on the fact that string that only takes 15 milliseconds to process is a
worse guess than ones that take more than 15 milliseconds. A 50 millisecond comparison in
this scenario means that @x is a 50% match of @y (from byte 1-8).
How? Set up a loop based on the length of @x and perform a byte by byte XOR. If @result is still 0
after all iterations then @x is equal to @y. If the comparison is meant to be secure then the
untrusted string should be @x and the trusted string should be @y.
*/
returns bit
with schemabinding
as
begin;
declare @i int = 0;
declare @l int = DataLength(@x);
declare @result int = @l - DataLength(@y);
while (@i < @l)
begin;
set @result = ((@result ^ Substring(@x, @i, 1)) ^ Substring(@y, @i, 1));
set @i = @i + 1;
end;
set @result = case @result when 0 then 1 else 0 end;
return @result;
end;