utils: Add a constant time memeq() variant for cryptographic purposes
This commit is contained in:
@@ -196,6 +196,12 @@ CALLBACK(attack_memeq4, bool,
|
|||||||
return !m;
|
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)
|
static bool attack_memeq(char *name, u_int iterations, u_int distance)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
@@ -206,6 +212,7 @@ static bool attack_memeq(char *name, u_int iterations, u_int distance)
|
|||||||
{ "memeq2", attack_memeq2 },
|
{ "memeq2", attack_memeq2 },
|
||||||
{ "memeq3", attack_memeq3 },
|
{ "memeq3", attack_memeq3 },
|
||||||
{ "memeq4", attack_memeq4 },
|
{ "memeq4", attack_memeq4 },
|
||||||
|
{ "memeq5", attack_memeq5 },
|
||||||
};
|
};
|
||||||
u_char exp[16];
|
u_char exp[16];
|
||||||
int i;
|
int i;
|
||||||
@@ -350,7 +357,7 @@ int main(int argc, char *argv[])
|
|||||||
if (argc < 3)
|
if (argc < 3)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage: %s <attack> <iterations> <distance>\n", argv[0]);
|
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, " <iterations>: number of invocations * 1000\n");
|
||||||
fprintf(stderr, " <distance>: time difference in ns for a hit\n");
|
fprintf(stderr, " <distance>: time difference in ns for a hit\n");
|
||||||
fprintf(stderr, " example: %s memeq1 100 500\n", argv[0]);
|
fprintf(stderr, " example: %s memeq1 100 500\n", argv[0]);
|
||||||
|
|||||||
@@ -306,6 +306,48 @@ START_TEST(test_memxor_aligned)
|
|||||||
}
|
}
|
||||||
END_TEST
|
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
|
* memstr
|
||||||
*/
|
*/
|
||||||
@@ -779,6 +821,11 @@ Suite *utils_suite_create()
|
|||||||
tcase_add_test(tc, test_memxor_aligned);
|
tcase_add_test(tc, test_memxor_aligned);
|
||||||
suite_add_tcase(s, tc);
|
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");
|
tc = tcase_create("memstr");
|
||||||
tcase_add_loop_test(tc, test_memstr, 0, countof(memstr_data));
|
tcase_add_loop_test(tc, test_memstr, 0, countof(memstr_data));
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|||||||
@@ -109,6 +109,25 @@ void memwipe_noinline(void *ptr, size_t n)
|
|||||||
memwipe_inline(ptr, n);
|
memwipe_inline(ptr, 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.
|
* Described in header.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -184,6 +184,11 @@ static inline bool memeq(const void *x, const void *y, size_t len)
|
|||||||
return memcmp(x, y, len) == 0;
|
return memcmp(x, y, len) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Calling memcpy() with NULL pointers, even with n == 0, results in undefined
|
||||||
* behavior according to the C standard. This version is guaranteed to not
|
* behavior according to the C standard. This version is guaranteed to not
|
||||||
|
|||||||
Reference in New Issue
Block a user