From 9d6e952201a1292087dc42b16a3055a99dbee7ba Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 11 Apr 2015 15:55:26 +0200 Subject: [PATCH] utils: Add a constant time chunk_equals() variant for cryptographic purposes --- scripts/timeattack.c | 48 ++++++++++++++++++++- src/libstrongswan/tests/suites/test_chunk.c | 27 ++++++++++++ src/libstrongswan/utils/chunk.h | 13 ++++++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/scripts/timeattack.c b/scripts/timeattack.c index 3d7ffee7d3..ef00e8c4e6 100644 --- a/scripts/timeattack.c +++ b/scripts/timeattack.c @@ -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 \n", argv[0]); - fprintf(stderr, " : memeq[1-5] / aead / signer\n"); + fprintf(stderr, " : memeq[1-5] / chunk[1-2] / aead / signer\n"); fprintf(stderr, " : number of invocations * 1000\n"); fprintf(stderr, " : 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])); } diff --git a/src/libstrongswan/tests/suites/test_chunk.c b/src/libstrongswan/tests/suites/test_chunk.c index b5d23658da..312a187ac4 100644 --- a/src/libstrongswan/tests/suites/test_chunk.c +++ b/src/libstrongswan/tests/suites/test_chunk.c @@ -60,6 +60,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"); diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index 48405b77eb..2ec7f7543b 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -309,6 +309,19 @@ static inline bool chunk_equals(chunk_t a, chunk_t b) a.len == b.len && memeq(a.ptr, b.ptr, a.len); } +/** + * 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. -- 2.47.2