mirror of
https://github.com/weechat/weechat.git
synced 2026-07-07 10:13:12 +02:00
relay: fix timing attack on password authentication (GHSA-vhv8-g2r9-cwcc)
The relay authentication used non-constant-time comparisons (strcasecmp, strcmp) to verify password hashes and plaintext passwords, allowing an attacker to derive the expected hash byte-by-byte from response timing and then authenticate without knowing the password. - SHA/PBKDF2 hex hash comparisons: normalize the client-supplied hash to uppercase and compare in constant time over the fixed expected length. - Plaintext password comparison: HMAC-SHA256 both passwords with a fresh per-call random key and compare the fixed-size MACs in constant time, hiding both per-byte timing and the password length. Add string_memcmp_constant_time helper in core, exposed via the plugin API. Bump WEECHAT_PLUGIN_API_VERSION accordingly.
This commit is contained in:
@@ -916,6 +916,43 @@ string_strcmp_ignore_chars (const char *string1, const char *string2,
|
||||
string_charcasecmp (string1, string2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two memory areas of the same size in constant time.
|
||||
*
|
||||
* Use to compare secrets (e.g. password hashes, MACs) without leaking
|
||||
* information through the comparison's running time. The loop always
|
||||
* walks the full "size" bytes and uses only bitwise operations on the
|
||||
* data, so the execution time depends on "size" alone, not on the
|
||||
* position of the first differing byte.
|
||||
*
|
||||
* If either pointer is NULL, the areas are considered different (the
|
||||
* NULL check itself is not constant time but does not look at any
|
||||
* secret content).
|
||||
*
|
||||
* Returns:
|
||||
* 0: areas are equal
|
||||
* 1: areas differ
|
||||
*/
|
||||
|
||||
int
|
||||
string_memcmp_constant_time (const void *area1, const void *area2, size_t size)
|
||||
{
|
||||
const unsigned char *p1, *p2;
|
||||
unsigned char diff;
|
||||
size_t i;
|
||||
|
||||
if (!area1 || !area2)
|
||||
return (area1 == area2) ? 0 : 1;
|
||||
|
||||
p1 = (const unsigned char *)area1;
|
||||
p2 = (const unsigned char *)area2;
|
||||
diff = 0;
|
||||
for (i = 0; i < size; i++)
|
||||
diff |= p1[i] ^ p2[i];
|
||||
|
||||
return (diff == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Searches for a string in another string (locale and case independent).
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user