summaryrefslogtreecommitdiffstats
path: root/app/helpers.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/helpers.php')
-rw-r--r--app/helpers.php57
1 files changed, 56 insertions, 1 deletions
diff --git a/app/helpers.php b/app/helpers.php
index 3bce65f..01d0086 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -1,6 +1,29 @@
<?php
/**
+ * Register polyfills for old PHP versions.
+ *
+ * This way, the real function will only be called if it
+ * is available, and we won't force the use of our own
+ * implementation.
+ */
+function register_polyfills()
+{
+ if (!function_exists('hash_equals')) {
+ function hash_equals($known_string, $user_string) {
+ call_user_func_array('_hash_equals', func_get_args());
+ }
+ }
+
+ if (!function_exists('random_bytes')) {
+ // If this function does not exist, it will be exposed
+ // automatically by paragonie/random_compat.
+ }
+}
+
+register_polyfills();
+
+/**
* Path to the _custom_ directory.
*
* @param string $file Append this filename to the returned path.
@@ -72,4 +95,36 @@ function removeCustomFiles()
unlink($path);
}
}
-} \ No newline at end of file
+}
+
+/**
+ * Compare two strings in a constant-time manner.
+ *
+ * It returns `true` if both strings are exactly the same
+ * (same size and same value).
+ *
+ * @param string $known_string
+ * @param string $user_string
+ * @return bool
+ */
+function _hash_equals($known_string = '', $user_string = '')
+{
+ // In our case, it's not problematic if `$known_string`'s
+ // size leaks, we will only compare password hashes and
+ // CSRF tokens—their size is already somehow public.
+ if (!is_string($known_string) || !is_string($user_string)
+ || strlen($known_string) !== strlen($user_string)) {
+ return false;
+ }
+
+ $ret = 0;
+
+ // Do not stop the comparison when a difference is found,
+ // always completely compare them.
+ for ($i = 0; $i < strlen($known_string); $i++) {
+ $ret |= (ord($known_string[$i]) ^ ord($user_string[$i]));
+ }
+
+ return !$ret;
+}
+