note 125034 deleted from function.hash-equals by cmb
| From: | cmb@php.net | Date: | Thu, 29 Jul 2021 12:42:11 +0000 |
| Subject: | note 125034 deleted from function.hash-equals by cmb | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-216682@lists.php.net to get a copy of this message | ||
Note Submitter: examplehash at user dot com
----
None of the polyfills for this function to date are actually correct. A timing attack defensive
string comparison function must not take *any* shortcuts. If the function performs a single if-then
statement other than validating input types (i.e. making sure inputs are strings), then it is doing
the comparison incorrectly. But I'd argue that by the time you call the function, your inputs
should have already been sanitized. The top-most voted item by asphp incorrectly shortcuts on a
comparison of strlen() (enabling a precision oracle attack on string length), while Markus shortcuts
on knownstring (enabling an oracle attack on length of knownstring), and others shortcut in similar
ways.
Here is a correct implementation in PHP adapted from a correct C implementation:
function CTstrcmp($secret, $userinput)
{
$sx = 0;
$sy = strlen($secret);
$uy = strlen($userinput);
$result = $sy - $uy;
for ($ux = 0; $ux < $uy; $ux++)
{
$result |= ord($userinput[$ux]) ^ ord($secret[$sx]);
$sx = ($sx + 1) % $sy;
}
return $result;
}
Here, every byte of userinput is executed over regardless of the length of either string. An oracle
length attack is not possible since there is no comparison of lengths - just assignment and math.
The amount of time spent in the function is entirely dependent upon the length of userinput and can
only be correct (i.e. return 0) if userinput exactly matches the secret. Please take your time to
understand the key differences between this function and the others.
If you are porting the above to another language, be aware of how strings and whatever strlen()
equivalent works behind the scenes in your language. PHP stores the size of the data separately so
it can strlen() in O(1) time.