return ret == 0;
}
+bool str_equals_timing_almost_safe(const char *s1, const char *s2)
+{
+ size_t i;
+ int ret = 0;
+
+ for (i = 0; s1[i] != '\0' && s2[i] != '\0'; i++)
+ ret |= s1[i] ^ s2[i];
+ ret |= s1[i] ^ s2[i];
+
+ /* make sure the compiler optimizer doesn't try to break out of the
+ above loop early. */
+ timing_safety_unoptimization = ret;
+ return ret == 0;
+}
+
size_t
str_match(const char *p1, const char *p2)
{
/* Returns TRUE if the two memory areas are equal. This function is safe
against timing attacks, so it compares all the bytes every time. */
bool mem_equals_timing_safe(const void *p1, const void *p2, size_t size);
+/* Returns TRUE if the two strings are equal. Similar to
+ mem_equals_timing_safe() this function is safe against timing attacks when
+ the string lengths are the same. If not, the length of the secret string may
+ be leaked, but otherwise the contents won't be. */
+bool str_equals_timing_almost_safe(const char *s1, const char *s2);
size_t str_match(const char *p1, const char *p2) ATTR_PURE;
static inline ATTR_PURE bool str_begins(const char *haystack, const char *needle)
test_end();
}
+static void test_str_equals_timing_almost_safe(void)
+{
+ const struct {
+ const char *a, *b;
+ } tests[] = {
+ { "", "" },
+ { "a", "a" },
+ { "b", "a" },
+ { "ab", "ab" },
+ { "ab", "ba" },
+ { "ab", "bc" },
+ { "a", "" },
+ { "a", "ab" },
+ { "a", "abc" },
+ { "ab", "abc" },
+ };
+ test_begin("str_equals_timing_almost_safe()");
+ for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
+ test_assert((strcmp(tests[i].a, tests[i].b) == 0) ==
+ str_equals_timing_almost_safe(tests[i].a, tests[i].b));
+ test_assert((strcmp(tests[i].a, tests[i].b) == 0) ==
+ str_equals_timing_almost_safe(tests[i].b, tests[i].a));
+ }
+ test_end();
+}
+
static void test_dec2str_buf(void)
{
const uintmax_t test_input[] = {
test_t_strarray_join();
test_p_array_const_string_join();
test_mem_equals_timing_safe();
+ test_str_equals_timing_almost_safe();
test_dec2str_buf();
test_str_match();
}