mirror of
https://github.com/jedisct1/libsodium.git
synced 2026-08-25 08:37:13 +09:00
Add sodium_compare()
A constant-time version of memcmp(), useful to compare nonces and counters in little-endian format, that plays well with sodium_increment(). Unlike sodium_memcmp() which can compare anything for equality, sodium_compare() is designed to compare things that are comparable, byte by byte. Therefore, the prototype is slightly different: its arguments are supposed to be `const unsigned char *`. The names sodium_memcmp() and sodium_compare() are slightly confusing. But we're not going to rename sodium_memcmp(), and I cannot think of a better name for sodium_compare() than sodium_compare().
This commit is contained in:
@@ -19,7 +19,8 @@ extern "C" {
|
||||
SODIUM_EXPORT
|
||||
void sodium_memzero(void * const pnt, const size_t len);
|
||||
|
||||
/* WARNING: sodium_memcmp() must be used to verify if two secret keys
|
||||
/*
|
||||
* WARNING: sodium_memcmp() must be used to verify if two secret keys
|
||||
* are equal, in constant time.
|
||||
* It returns 0 if the keys are equal, and -1 if they differ.
|
||||
* This function is not designed for lexicographical comparisons.
|
||||
@@ -27,6 +28,19 @@ void sodium_memzero(void * const pnt, const size_t len);
|
||||
SODIUM_EXPORT
|
||||
int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len);
|
||||
|
||||
/*
|
||||
* sodium_compare() returns -1 if b1_ < b2_, 1 if b1_ > b2_ and 0 if b1_ == b2_
|
||||
* It is suitable for lexicographical comparisons, or to compare nonces
|
||||
* and counters stored in little-endian format.
|
||||
* However, it is slower than sodium_memcmp().
|
||||
*/
|
||||
SODIUM_EXPORT
|
||||
int sodium_compare(const unsigned char *b1_, const unsigned char *b2_,
|
||||
size_t len);
|
||||
|
||||
SODIUM_EXPORT
|
||||
void sodium_increment(unsigned char *n, const size_t nlen);
|
||||
|
||||
SODIUM_EXPORT
|
||||
char *sodium_bin2hex(char * const hex, const size_t hex_maxlen,
|
||||
const unsigned char * const bin, const size_t bin_len);
|
||||
@@ -95,9 +109,6 @@ int sodium_mprotect_readonly(void *ptr);
|
||||
SODIUM_EXPORT
|
||||
int sodium_mprotect_readwrite(void *ptr);
|
||||
|
||||
SODIUM_EXPORT
|
||||
void sodium_increment(unsigned char *n, const size_t nlen);
|
||||
|
||||
/* -------- */
|
||||
|
||||
int _sodium_alloc_init(void);
|
||||
|
||||
@@ -116,6 +116,42 @@ sodium_memcmp(const void * const b1_, const void * const b2_, size_t len)
|
||||
return (int) ((1 & ((d - 1) >> 8)) - 1);
|
||||
}
|
||||
|
||||
#ifdef HAVE_WEAK_SYMBOLS
|
||||
__attribute__((weak)) void
|
||||
_sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1,
|
||||
const unsigned char *b2,
|
||||
const size_t len)
|
||||
{
|
||||
(void) b1;
|
||||
(void) b2;
|
||||
(void) len;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
sodium_compare(const unsigned char *b1_, const unsigned char *b2_, size_t len)
|
||||
{
|
||||
#ifdef HAVE_WEAK_SYMBOLS
|
||||
const unsigned char *b1 = b1_;
|
||||
const unsigned char *b2 = b2_;
|
||||
#else
|
||||
const volatile unsigned char *b1 = (const volatile unsigned char *) b1_;
|
||||
const volatile unsigned char *b2 = (const volatile unsigned char *) b2_;
|
||||
#endif
|
||||
unsigned char gt = 0U;
|
||||
unsigned char eq = 1U;
|
||||
size_t i;
|
||||
|
||||
#if HAVE_WEAK_SYMBOLS
|
||||
_sodium_dummy_symbol_to_prevent_compare_lto(b1, b2, len);
|
||||
#endif
|
||||
for (i = (size_t) 0U; i < len; i++) {
|
||||
gt |= ((b2[i] - b1[i]) >> 8) & eq;
|
||||
eq &= ((b2[i] ^ b1[i]) - 1) >> 8;
|
||||
}
|
||||
return (int) (gt + gt + eq) - 1;
|
||||
}
|
||||
|
||||
/* Derived from original code by CodesInChaos */
|
||||
char *
|
||||
sodium_bin2hex(char * const hex, const size_t hex_maxlen,
|
||||
|
||||
@@ -13,6 +13,7 @@ int main(void)
|
||||
const char *hex;
|
||||
const char *hex_end;
|
||||
size_t bin_len;
|
||||
int i;
|
||||
|
||||
randombytes_buf(buf1, sizeof buf1);
|
||||
memcpy(buf2, buf1, sizeof buf2);
|
||||
@@ -83,5 +84,18 @@ int main(void)
|
||||
sodium_increment(nonce, sizeof nonce);
|
||||
printf("%s\n", sodium_bin2hex(nonce_hex, sizeof nonce_hex,
|
||||
nonce, sizeof nonce));
|
||||
for (i = 0; i < 1000; i++) {
|
||||
bin_len = (size_t) randombytes_uniform(sizeof buf1);
|
||||
randombytes_buf(buf1, bin_len);
|
||||
randombytes_buf(buf2, bin_len);
|
||||
if (memcmp(buf1, buf2, bin_len) *
|
||||
sodium_compare(buf1, buf2, bin_len) < 0) {
|
||||
printf("sodium_compare() failure with length=%zu\n", bin_len);
|
||||
}
|
||||
memcpy(buf1, buf2, bin_len);
|
||||
if (sodium_compare(buf1, buf2, bin_len)) {
|
||||
printf("sodium_compare() equality failure with length=%zu\n", bin_len);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user