summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Ferrara <me@ircmaxell.com>2012-12-29 07:51:01 -0500
committerAnthony Ferrara <me@ircmaxell.com>2012-12-29 07:51:01 -0500
commit6ef999b2d566c59819f99e0eeab77940fbd0d77c (patch)
treeb53e86cbd604e3d75eede9ab92cd6795a3e1f529
parent1849d1e5d8f925c671ba44ce461859c730298edb (diff)
downloadsymfony-security-6ef999b2d566c59819f99e0eeab77940fbd0d77c.zip
symfony-security-6ef999b2d566c59819f99e0eeab77940fbd0d77c.tar.gz
symfony-security-6ef999b2d566c59819f99e0eeab77940fbd0d77c.tar.bz2
Improve timing safe comparison function
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.
-rw-r--r--Core/Util/StringUtils.php31
1 files changed, 21 insertions, 10 deletions
diff --git a/Core/Util/StringUtils.php b/Core/Util/StringUtils.php
index d21efd3..b13408a 100644
--- a/Core/Util/StringUtils.php
+++ b/Core/Util/StringUtils.php
@@ -28,22 +28,33 @@ class StringUtils
*
* This method implements a constant-time algorithm to compare strings.
*
- * @param string $str1 The first string
- * @param string $str2 The second string
+ * @param string $knownString The string of known length to compare against
+ * @param string $userInput The string that the user can control
*
* @return Boolean true if the two strings are the same, false otherwise
*/
- public static function equals($str1, $str2)
+ public static function equals($knownString, $userInput)
{
- if (strlen($str1) !== $c = strlen($str2)) {
- return false;
- }
+ // Prevent issues if string length is 0
+ $knownString .= chr(0);
+ $userInput .= chr(0);
+
+ $knownLen = strlen($knownString);
+ $userLen = strlen($userInput);
+
+ // Set the result to the difference between the lengths
+ $result = $knownLen - $userLen;
- $result = 0;
- for ($i = 0; $i < $c; $i++) {
- $result |= ord($str1[$i]) ^ ord($str2[$i]);
+ // Note that we ALWAYS iterate over the user-supplied length
+ // This is to prevent leaking length information
+ for ($i = 0; $i < $userLen; $i++) {
+ // Using % here is a trick to prevent notices
+ // It's safe, since if the lengths are different
+ // $result is already non-0
+ $result |= (ord($knownString[$i % $knownLen]) ^ ord($userInput[$i]));
}
- return 0 === $result;
+ // They are only identical strings if $result is exactly 0...
+ return $result === 0;
}
}