utils: Add a constant time chunk_equals() variant for cryptographic purposes
authorMartin Willi <martin@revosec.ch>
Sat, 11 Apr 2015 13:55:26 +0000 (15:55 +0200)
committerMartin Willi <martin@revosec.ch>
Tue, 14 Apr 2015 10:02:48 +0000 (12:02 +0200)
scripts/timeattack.c
src/libstrongswan/tests/suites/test_chunk.c
src/libstrongswan/utils/chunk.h

index 3d7ffee..ef00e8c 100644 (file)
@@ -235,6 +235,48 @@ static bool attack_memeq(char *name, u_int iterations, u_int distance)
        return FALSE;
 }
 
+CALLBACK(attack_chunk1, bool,
+       u_char *subj, u_char *data, size_t len)
+{
+       return chunk_equals(chunk_create(subj, len), chunk_create(data, len));
+}
+
+CALLBACK(attack_chunk2, bool,
+       u_char *subj, u_char *data, size_t len)
+{
+       return chunk_equals_const(chunk_create(subj, len), chunk_create(data, len));
+}
+
+static bool attack_chunk(char *name, u_int iterations, u_int distance)
+{
+       struct {
+               char *name;
+               attackfn_t fn;
+       } attacks[] = {
+               { "chunk1", attack_chunk1 },
+               { "chunk2", attack_chunk2 },
+       };
+       u_char exp[16];
+       int i;
+
+       srandom(time(NULL));
+       for (i = 0; i < sizeof(exp); i++)
+       {
+               exp[i] = random();
+       }
+       fprintf(stderr, "attacking %b\n", exp, sizeof(exp));
+
+       for (i = 0; i < countof(attacks); i++)
+       {
+               if (streq(name, attacks[i].name))
+               {
+                       return timeattack(attacks[i].fn, exp, sizeof(exp),
+                                                         iterations, distance);
+               }
+       }
+       return FALSE;
+}
+
 CALLBACK(attack_aead, bool,
        aead_t *aead, u_char *data, size_t len)
 {
@@ -357,7 +399,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-5] / aead / signer\n");
+               fprintf(stderr, "  <attack>: memeq[1-5] / chunk[1-2] / 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]);
@@ -368,5 +410,9 @@ int main(int argc, char *argv[])
        {
                return !attack_memeq(argv[1], atoi(argv[2]), atoi(argv[3]));
        }
+       if (strpfx(argv[1], "chunk"))
+       {
+               return !attack_chunk(argv[1], atoi(argv[2]), atoi(argv[3]));
+       }
        return !attack_transform(argv[1], atoi(argv[2]), atoi(argv[3]));
 }
index b5d2365..312a187 100644 (file)
@@ -61,6 +61,32 @@ START_TEST(test_chunk_equals)
 END_TEST
 
 /*******************************************************************************
+ * equals_const
+ */
+
+START_TEST(test_chunk_equals_const)
+{
+       chunk_t chunk = chunk_from_str("chunk");
+       chunk_t chunk_a, chunk_b;
+
+       chunk_a = chunk_empty;
+       chunk_b = chunk_empty;
+       ck_assert(!chunk_equals_const(chunk_a, chunk_b));
+
+       chunk_a = chunk;
+       ck_assert(!chunk_equals_const(chunk_a, chunk_b));
+       chunk_b = chunk;
+       ck_assert(chunk_equals_const(chunk_a, chunk_b));
+
+       chunk_b = chunk_from_str("asdf");
+       ck_assert(!chunk_equals_const(chunk_a, chunk_b));
+
+       chunk_b = chunk_from_str("chunk");
+       ck_assert(chunk_equals_const(chunk_a, chunk_b));
+}
+END_TEST
+
+/*******************************************************************************
  * chunk_compare test
  */
 
@@ -1013,6 +1039,7 @@ Suite *chunk_suite_create()
 
        tc = tcase_create("equals");
        tcase_add_test(tc, test_chunk_equals);
+       tcase_add_test(tc, test_chunk_equals_const);
        suite_add_tcase(s, tc);
 
        tc = tcase_create("chunk_compare");
index 48405b7..2ec7f75 100644 (file)
@@ -310,6 +310,19 @@ static inline bool chunk_equals(chunk_t a, chunk_t b)
 }
 
 /**
+ * Compare two chunks for equality, constant time for cryptographic purposes.
+ *
+ * Note that this function is constant time only for chunks with the same
+ * length, i.e. it does not protect against guessing the length of one of the
+ * chunks.
+ */
+static inline bool chunk_equals_const(chunk_t a, chunk_t b)
+{
+       return a.ptr != NULL  && b.ptr != NULL &&
+                       a.len == b.len && memeq_const(a.ptr, b.ptr, a.len);
+}
+
+/**
  * Compare two chunks (given as pointers) for equality (useful as callback),
  * NULL chunks are never equal.
  */