utils: Add a constant time memeq() variant for cryptographic purposes
authorMartin Willi <martin@revosec.ch>
Sat, 11 Apr 2015 14:44:18 +0000 (16:44 +0200)
committerMartin Willi <martin@revosec.ch>
Tue, 14 Apr 2015 09:51:54 +0000 (11:51 +0200)
scripts/timeattack.c
src/libstrongswan/tests/suites/test_utils.c
src/libstrongswan/utils/utils.c
src/libstrongswan/utils/utils.h

index 0a53aba..3d7ffee 100644 (file)
@@ -196,6 +196,12 @@ CALLBACK(attack_memeq4, bool,
        return !m;
 }
 
+CALLBACK(attack_memeq5, bool,
+       u_char *subj, u_char *data, size_t len)
+{
+       return memeq_const(subj, data, len);
+}
+
 static bool attack_memeq(char *name, u_int iterations, u_int distance)
 {
        struct {
@@ -206,6 +212,7 @@ static bool attack_memeq(char *name, u_int iterations, u_int distance)
                { "memeq2", attack_memeq2 },
                { "memeq3", attack_memeq3 },
                { "memeq4", attack_memeq4 },
+               { "memeq5", attack_memeq5 },
        };
        u_char exp[16];
        int i;
@@ -350,7 +357,7 @@ int main(int argc, char *argv[])
        if (argc < 3)
        {
                fprintf(stderr, "usage: %s <attack> <iterations> <distance>\n", argv[0]);
-               fprintf(stderr, "  <attack>: memeq[1-4] / aead / signer\n");
+               fprintf(stderr, "  <attack>: memeq[1-5] / aead / signer\n");
                fprintf(stderr, "  <iterations>: number of invocations * 1000\n");
                fprintf(stderr, "  <distance>: time difference in ns for a hit\n");
                fprintf(stderr, "  example: %s memeq1 100 500\n", argv[0]);
index 85a8544..f151fb3 100644 (file)
@@ -307,6 +307,48 @@ START_TEST(test_memxor_aligned)
 END_TEST
 
 /*******************************************************************************
+ * memeq/const
+ */
+
+static struct {
+       char *a;
+       char *b;
+       size_t n;
+       bool res;
+} memeq_data[] = {
+       {NULL, NULL, 0, TRUE},
+       {"a", "b", 0, TRUE},
+       {"", "", 1, TRUE},
+       {"abcdefgh", "abcdefgh", 8, TRUE},
+       {"a", "b", 1, FALSE},
+       {"A", "a", 1, FALSE},
+       {"\0a", "\0b", 2, FALSE},
+       {"abc", "abd", 3, FALSE},
+       {"abc", "dbd", 3, FALSE},
+       {"abcdefgh", "abcdffgh", 8, FALSE},
+       {"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
+        "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 52, TRUE},
+       {"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
+        "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyy", 52, FALSE},
+       {"bbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
+        "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 52, FALSE},
+};
+
+START_TEST(test_memeq)
+{
+       ck_assert(memeq(memeq_data[_i].a, memeq_data[_i].b,
+                                       memeq_data[_i].n) == memeq_data[_i].res);
+}
+END_TEST
+
+START_TEST(test_memeq_const)
+{
+       ck_assert(memeq_const(memeq_data[_i].a, memeq_data[_i].b,
+                                                 memeq_data[_i].n) == memeq_data[_i].res);
+}
+END_TEST
+
+/*******************************************************************************
  * memstr
  */
 
@@ -779,6 +821,11 @@ Suite *utils_suite_create()
        tcase_add_test(tc, test_memxor_aligned);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("memeq");
+       tcase_add_loop_test(tc, test_memeq, 0, countof(memeq_data));
+       tcase_add_loop_test(tc, test_memeq_const, 0, countof(memeq_data));
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("memstr");
        tcase_add_loop_test(tc, test_memstr, 0, countof(memstr_data));
        suite_add_tcase(s, tc);
index 02a7209..3d5e3df 100644 (file)
@@ -112,6 +112,25 @@ void memwipe_noinline(void *ptr, size_t n)
 /**
  * Described in header.
  */
+bool memeq_const(const void *x, const void *y, size_t len)
+{
+       const u_char *a, *b;
+       u_int bad = 0;
+       size_t i;
+
+       a = (const u_char*)x;
+       b = (const u_char*)y;
+
+       for (i = 0; i < len; i++)
+       {
+               bad |= a[i] != b[i];
+       }
+       return !bad;
+}
+
+/**
+ * Described in header.
+ */
 void *memstr(const void *haystack, const char *needle, size_t n)
 {
        const u_char *pos = haystack;
index 7c48d94..2675aca 100644 (file)
@@ -185,6 +185,11 @@ static inline bool memeq(const void *x, const void *y, size_t len)
 }
 
 /**
+ * Same as memeq(), but with a constant runtime, safe for cryptographic use.
+ */
+bool memeq_const(const void *x, const void *y, size_t len);
+
+/**
  * Calling memcpy() with NULL pointers, even with n == 0, results in undefined
  * behavior according to the C standard.  This version is guaranteed to not
  * access the pointers if n is 0.