diff --git a/include/haproxy/tools-t.h b/include/haproxy/tools-t.h index 77911dd85..792a0f650 100644 --- a/include/haproxy/tools-t.h +++ b/include/haproxy/tools-t.h @@ -188,4 +188,12 @@ struct file_name_node { char name[VAR_ARRAY]; /* storage, used with cebus_*() */ }; +/* a pair of uint64_t. It's purposely arranged in little endian to help + * being vectorized on modern processors. + */ +struct uint64_pair { + uint64_t l; + uint64_t h; +}; + #endif /* _HAPROXY_TOOLS_T_H */ diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 6e4758509..3b6e0a338 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -1288,6 +1288,8 @@ static inline void _ha_aligned_free(void *ptr) int parse_dotted_uints(const char *s, unsigned int **nums, size_t *sz); /* PRNG */ +struct uint64_pair _ha_random64_pair_hashed(void); + void ha_generate_uuid_v4(struct buffer *output); void ha_generate_uuid_v7(struct buffer *output); void ha_random_seed(const unsigned char *seed, size_t len); @@ -1295,6 +1297,17 @@ void ha_random_jump96(uint32_t dist); uint64_t ha_random64(void); uint64_t ha_random64_internal(void); +/* Returns a pair of uint64_t randoms hashed so as not to disclose the internal + * PRNG state. + */ +static inline void ha_random64_pair_hashed(uint64_t *l, uint64_t *h) +{ + struct uint64_pair ret = _ha_random64_pair_hashed(); + + *l = ret.l; + *h = ret.h; +} + static inline uint32_t ha_random32() { return ha_random64() >> 32; diff --git a/src/tools.c b/src/tools.c index 578d38d1f..f9825826d 100644 --- a/src/tools.c +++ b/src/tools.c @@ -6297,6 +6297,23 @@ uint64_t ha_random64(void) now_ns); } +/* Returns a pair of uint64_t randoms hashed so as not to disclose the internal + * PRNG state. This function shouldn't be used directly, better use the public + * ha_random64_pair_hashed() which calls it. The function uses a local XXH + * secret that is created at boot, and now_ns as the seed to limit remote + * analysis. + */ +struct uint64_pair _ha_random64_pair_hashed(void) +{ + XXH128_hash_t ret; + ret = XXH3_128bits_withSecretandSeed(ha_random_state, 2*sizeof(uint64_t), + ha_random_xxh_secret, sizeof(ha_random_xxh_secret), + now_ns); + /* update the internal state */ + ha_random64_internal(); + return (struct uint64_pair){ .l = ret.low64, .h = ret.high64 }; +} + /* seeds the random state using up to bytes from , starting with * the first non-zero byte. */