diff options
author | Martin Willi <martin@revosec.ch> | 2015-04-11 16:44:18 +0200 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2015-04-14 11:51:54 +0200 |
commit | b833963270fbffe3186f5c71c7584c2347a44038 (patch) | |
tree | 75e2d440ec3f27ca6f25b899c592e51258e21c26 | |
parent | 39e1ddec2ed3480e0edc07bbabfacbf907dc4e3f (diff) | |
download | strongswan-b833963270fbffe3186f5c71c7584c2347a44038.tar.bz2 strongswan-b833963270fbffe3186f5c71c7584c2347a44038.tar.xz |
utils: Add a constant time memeq() variant for cryptographic purposes
-rw-r--r-- | scripts/timeattack.c | 9 | ||||
-rw-r--r-- | src/libstrongswan/tests/suites/test_utils.c | 47 | ||||
-rw-r--r-- | src/libstrongswan/utils/utils.c | 19 | ||||
-rw-r--r-- | src/libstrongswan/utils/utils.h | 5 |
4 files changed, 79 insertions, 1 deletions
diff --git a/scripts/timeattack.c b/scripts/timeattack.c index 0a53abae9..3d7ffee7d 100644 --- a/scripts/timeattack.c +++ b/scripts/timeattack.c @@ -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]); diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c index 85a854456..f151fb35e 100644 --- a/src/libstrongswan/tests/suites/test_utils.c +++ b/src/libstrongswan/tests/suites/test_utils.c @@ -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); diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c index 02a720945..3d5e3dfc9 100644 --- a/src/libstrongswan/utils/utils.c +++ b/src/libstrongswan/utils/utils.c @@ -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; diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index 7c48d949f..2675acae8 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -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. |