Skip to content

Commit 11b0dae

Browse files
committed
merged branch ircmaxell/master (PR symfony#6510)
This PR was merged into the master branch. Commits ------- c543116 Improve timing safe comparison function Discussion ---------- Improve timing safe comparison function in Security bundle to not leak length information. Improve the timing safe comparison function to better handle cases where input is of different length. Note that it is now important to always pass any string that the user can directly control to the second parameter of the function. Otherwise, length information may be leaked. --------------------------------------------------------------------------- by ircmaxell at 2012-12-29T13:36:32Z @apfelbox: No, for two reasons. First, you shouldn't be passing the password directly into this function (it should be hashed first). Second, it depends only on the length of the user supplied input (the second parameter). So the execution time will vary, but 100% based on user input. No information about the stored string is leaked... --------------------------------------------------------------------------- by apfelbox at 2012-12-29T14:09:54Z @ircmaxell yes, I just thought about it for a while and you are right. The `strlen($knownString)` is a constant factor and therefore the execution time of the function does not vary with it (especially if it is hashed).
2 parents 79148f3 + c543116 commit 11b0dae

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

src/Symfony/Component/Security/Core/Util/StringUtils.php

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,33 @@ private function __construct() {}
2828
*
2929
* This method implements a constant-time algorithm to compare strings.
3030
*
31-
* @param string $str1 The first string
32-
* @param string $str2 The second string
31+
* @param string $knownString The string of known length to compare against
32+
* @param string $userInput The string that the user can control
3333
*
3434
* @return Boolean true if the two strings are the same, false otherwise
3535
*/
36-
public static function equals($str1, $str2)
36+
public static function equals($knownString, $userInput)
3737
{
38-
if (strlen($str1) !== $c = strlen($str2)) {
39-
return false;
40-
}
38+
// Prevent issues if string length is 0
39+
$knownString .= chr(0);
40+
$userInput .= chr(0);
41+
42+
$knownLen = strlen($knownString);
43+
$userLen = strlen($userInput);
44+
45+
// Set the result to the difference between the lengths
46+
$result = $knownLen - $userLen;
4147

42-
$result = 0;
43-
for ($i = 0; $i < $c; $i++) {
44-
$result |= ord($str1[$i]) ^ ord($str2[$i]);
48+
// Note that we ALWAYS iterate over the user-supplied length
49+
// This is to prevent leaking length information
50+
for ($i = 0; $i < $userLen; $i++) {
51+
// Using % here is a trick to prevent notices
52+
// It's safe, since if the lengths are different
53+
// $result is already non-0
54+
$result |= (ord($knownString[$i % $knownLen]) ^ ord($userInput[$i]));
4555
}
4656

47-
return 0 === $result;
57+
// They are only identical strings if $result is exactly 0...
58+
return $result === 0;
4859
}
4960
}

0 commit comments

Comments
 (0)