memory: Add helper function to conditionally copy data in constant time
This commit is contained in:
@@ -539,6 +539,40 @@ START_TEST(test_memeq_const)
|
|||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* memcpy_cond
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MEMCPY_COND_DEF "abcdef"
|
||||||
|
static struct {
|
||||||
|
char *a;
|
||||||
|
size_t n;
|
||||||
|
uint8_t cond;
|
||||||
|
char *res;
|
||||||
|
} memcpy_cond_data[] = {
|
||||||
|
{NULL, 0, 0, NULL},
|
||||||
|
{NULL, 0, 1, NULL},
|
||||||
|
{"foobar", 6, 0, MEMCPY_COND_DEF},
|
||||||
|
{"foobar", 6, 1, "foobar"},
|
||||||
|
{"foobar", 3, 0, MEMCPY_COND_DEF},
|
||||||
|
{"foobar", 3, 1, "foodef"},
|
||||||
|
{"\0bar", 4, 0, MEMCPY_COND_DEF},
|
||||||
|
{"\0bar", 4, 1, "\0baref"},
|
||||||
|
/* unpredictable results if condition is not 0 or 1 */
|
||||||
|
{"foobar", 6, 5, "bkkfev"},
|
||||||
|
};
|
||||||
|
|
||||||
|
START_TEST(test_memcpy_cond)
|
||||||
|
{
|
||||||
|
char buf[BUF_LEN] = MEMCPY_COND_DEF;
|
||||||
|
|
||||||
|
memcpy_cond(buf, memcpy_cond_data[_i].a, memcpy_cond_data[_i].n,
|
||||||
|
memcpy_cond_data[_i].cond);
|
||||||
|
ck_assert(memeq(buf, memcpy_cond_data[_i].res ?: MEMCPY_COND_DEF,
|
||||||
|
sizeof(MEMCPY_COND_DEF)));
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* memstr
|
* memstr
|
||||||
*/
|
*/
|
||||||
@@ -1346,6 +1380,10 @@ Suite *utils_suite_create()
|
|||||||
tcase_add_loop_test(tc, test_memeq_const, 0, countof(memeq_data));
|
tcase_add_loop_test(tc, test_memeq_const, 0, countof(memeq_data));
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
tc = tcase_create("memcpy_cond");
|
||||||
|
tcase_add_loop_test(tc, test_memcpy_cond, 0, countof(memcpy_cond_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);
|
||||||
|
|||||||
@@ -90,6 +90,27 @@ bool memeq_const(const void *x, const void *y, size_t len)
|
|||||||
return !bad;
|
return !bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header
|
||||||
|
*/
|
||||||
|
void memcpy_cond(void *dst, const void *src, size_t n, uint8_t cond)
|
||||||
|
{
|
||||||
|
uint8_t *a;
|
||||||
|
const uint8_t *b;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
a = (uint8_t*)dst;
|
||||||
|
b = (const uint8_t*)src;
|
||||||
|
|
||||||
|
/* either 0xff or 0 */
|
||||||
|
cond = -cond;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
a[i] ^= cond & (a[i] ^ b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Described in header.
|
* Described in header.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -54,6 +54,15 @@ static inline void *memcpy_noop(void *dst, const void *src, size_t n)
|
|||||||
#endif
|
#endif
|
||||||
#define memcpy(d,s,n) memcpy_noop(d,s,n)
|
#define memcpy(d,s,n) memcpy_noop(d,s,n)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies n bytes from src to dst if the given condition is 1, or leaves dst
|
||||||
|
* unchanged if it's 0 (but does write to it).
|
||||||
|
*
|
||||||
|
* Runs in constant time, so it's safe to conditionally copy data after a call
|
||||||
|
* to memeq_const() without any branching instructions.
|
||||||
|
*/
|
||||||
|
void memcpy_cond(void *dst, const void *src, size_t n, uint8_t cond);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calling memmove() with NULL pointers, even with n == 0, results in undefined
|
* Calling memmove() 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