From: Vladimír Čunát Date: Mon, 17 Sep 2018 15:37:16 +0000 (+0200) Subject: buffer randomness from gnutls X-Git-Tag: v3.2.0~13^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=98cb95925a6fd64bfd5b1a0e55e9bafde0c574dd;p=thirdparty%2Fknot-resolver.git buffer randomness from gnutls gnutls_rnd() is more heavy-weight than I originally anticipated, and in simple profiling it would take roughly 1% of CPU. With this simple buffering the usage dropped well under 0.1%. --- diff --git a/lib/utils.c b/lib/utils.c index 2dd3a8544..af43f2277 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -989,6 +989,40 @@ finish: return d - dst; } +static void rnd_noerror(void *data, uint size) +{ + int ret = gnutls_rnd(GNUTLS_RND_NONCE, data, size); + if (ret) { + kr_log_error("gnutls_rnd(): %s\n", gnutls_strerror(ret)); + abort(); + } +} +void kr_rnd_buffered(void *data, uint size) +{ + /* static circular buffer, from index _begin (inclusive) to _end (exclusive) */ + static uint8_t buf[512/8]; /* gnutls_rnd() works on blocks of 512 bits (chacha) */ + static uint buf_begin = sizeof(buf); + + if (unlikely(size > sizeof(buf))) { + rnd_noerror(data, size); + return; + } + /* Start with contiguous chunk, possibly until the end of buffer. */ + const uint size1 = MIN(size, sizeof(buf) - buf_begin); + uint8_t *d = data; + memcpy(d, buf + buf_begin, size1); + if (size1 == size) { + buf_begin += size1; + return; + } + d += size1; + size -= size1; + /* Refill the whole buffer, and finish by another contiguous chunk. */ + rnd_noerror(buf, sizeof(buf)); + memcpy(d, buf, size); + buf_begin = size; +} + void kr_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner, uint16_t type, uint16_t rclass, uint32_t ttl) { diff --git a/lib/utils.h b/lib/utils.h index fc435bb78..67a552d6d 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -183,23 +183,21 @@ typedef array_t(ranked_rr_array_entry_t *) ranked_rr_array_t; KR_EXPORT char* kr_strcatdup(unsigned n, ...); +/** You probably want kr_rand_* convenience functions instead. + * This is a buffered version of gnutls_rnd(GNUTLS_RND_NONCE, ..) */ +KR_EXPORT +void kr_rnd_buffered(void *data, unsigned int size); + /** Return a few random bytes. */ static inline uint64_t kr_rand_bytes(int size) { - /* LATER(optim.): we use this to get one or two bytes typically, - * so it will probably be suitable to wrap the gnutls function - * by a buffer (size to be determined by profiling, perhaps). */ uint64_t result; if (size <= 0 || size > sizeof(result)) { kr_log_error("kr_rand_bytes(): EINVAL\n"); abort(); } uint8_t data[sizeof(result)]; - int ret = gnutls_rnd(GNUTLS_RND_NONCE, data, size); - if (ret) { - kr_log_error("gnutls_rnd(): %s\n", gnutls_strerror(ret)); - abort(); - } + kr_rnd_buffered(data, size); /* I would have liked to dump the random data into a size_t directly, * but that would work well only on little-endian machines, * so intsead I hope that the compiler will optimize this out.