diff options
author | Werner Koch <[email protected]> | 2025-03-14 12:03:46 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2025-03-14 12:08:37 +0000 |
commit | 926b1f1f1e3e382f08cc57fc86d5892649514007 (patch) | |
tree | ddc1bab10152c7de64a9c4167620f0683eac4a7f /src | |
parent | m4: Update libassuan.m4. (diff) | |
download | gpgme-926b1f1f1e3e382f08cc57fc86d5892649514007.tar.gz gpgme-926b1f1f1e3e382f08cc57fc86d5892649514007.zip |
Add API gpgme_op_random_value.
* src/genrandom.c (getrandom_size_t): New.
(gpgme_op_random_value): New.
* src/gpgme.def: Add new function.
* src/libgpgme.vers: Ditto.
* src/gpgme.h.in: Add prototype.
* tests/run-genrandom.c: Add an option to use the new function.
--
The implementation is not optimized but sufficient for our use case.
Possible improvements for this and gpgme_op_random_bytes are a cache
for random bytes in the context so that we do not need to get out to
gpgme for just a few random bytes.
GnuPG-bug-id: 6694
Diffstat (limited to 'src')
-rw-r--r-- | src/genrandom.c | 83 | ||||
-rw-r--r-- | src/gpgme.def | 1 | ||||
-rw-r--r-- | src/gpgme.h.in | 7 | ||||
-rw-r--r-- | src/libgpgme.vers | 1 |
4 files changed, 91 insertions, 1 deletions
diff --git a/src/genrandom.c b/src/genrandom.c index a4baa0b2..0f787cf4 100644 --- a/src/genrandom.c +++ b/src/genrandom.c @@ -58,6 +58,46 @@ do_genrandom (gpgme_ctx_t ctx, gpgme_data_t dataout, size_t length, int zbase) } +/* Store a random value into RETVAL or return an error. */ +static gpgme_error_t +getrandom_size_t (gpgme_ctx_t ctx, size_t *retval) +{ + gpgme_error_t err = 0; + gpgme_data_t data = NULL; + char *datap = NULL; + size_t datalen; + + err = gpgme_data_new (&data); + if (err) + goto leave; + + err = do_genrandom (ctx, data, sizeof (size_t), 0); + if (!err) + err = _gpgme_wait_one (ctx); + if (err) + goto leave; + + datap = gpgme_data_release_and_get_mem (data, &datalen); + data = NULL; + if (!datap) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (datalen != sizeof (size_t)) + { + err = gpg_error (GPG_ERR_INTERNAL); + goto leave; + } + memcpy (retval, datap, datalen); + + leave: + free (datap); + gpgme_data_release (data); + return err; +} + + /* Fill BUFFER of size BUFSIZE with random bytes retrieved from gpg. * If GPGME_RANDOM_MODE_ZBASE32 is used BUFSIZE needs to be at least * 31 and will be filled with a string of 30 ascii characters followed @@ -147,3 +187,46 @@ gpgme_op_random_bytes (gpgme_ctx_t ctx, gpgme_random_mode_t mode, gpgme_data_release (data); return TRACE_ERR (err); } + + + +/* On success the function stores an unbiased random value in the + * range [0,limit) at RETVAL. On error the function returns an error + * code and the value at RETVAL is undefined. A context must be + * provided so that the function can get raw random bytes from the gpg + * enine (i.e. from Libgcrypt). */ +gpgme_error_t +gpgme_op_random_value (gpgme_ctx_t ctx, size_t limit, size_t *retval) +{ + gpgme_error_t err; + size_t t, x; + + TRACE_BEG (DEBUG_CTX, "gpgme_op_random_value", ctx, "limit=%zu", limit); + + if (!ctx || limit < 2 || !retval) + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; + } + + /* This is the OpenBSD algorithm as used by arc4random_uniform and + * described in "Fast Random Integer Generation in an Interval" by + * Daniel Lemire (arXiv:1805.10941v4, 2018). */ + t = (-limit) % limit; + x = 0; /* Avoid (false) compiler warning. */ + do + { + err = getrandom_size_t (ctx, &x); + if (err) + goto leave; + /* fprintf (stderr, "getrandom returned %zu (limit=%zu, t=%zu)\n", */ + /* x, limit, t); */ + } + while (x < t); + x %= limit; + + *retval = x; + + leave: + return TRACE_ERR (err); +} diff --git a/src/gpgme.def b/src/gpgme.def index d203901f..3bdaac4e 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -276,4 +276,5 @@ EXPORTS gpgme_op_setownertrust_start @214 gpgme_op_random_bytes @215 + gpgme_op_random_value @216 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 9c0c7977..705d9741 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -2481,10 +2481,15 @@ typedef enum } gpgme_random_mode_t; -/* Fill BUFFER with BUFSIZE random bytes from gpg. */ +/* Fill BUFFER with BUFSIZE random bytes from gpg or return an error. */ gpgme_error_t gpgme_op_random_bytes (gpgme_ctx_t ctx, gpgme_random_mode_t mode, char *buffer, size_t bufsize); +/* Store an unbiased random value in the range [0,LIMIT) at RETVAL or + * return an error. */ +gpgme_error_t gpgme_op_random_value (gpgme_ctx_t ctx, size_t limit, + size_t *retval); + /* diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 83f8c87b..555f9fc0 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -274,6 +274,7 @@ GPGME_1.0 { gpgme_op_setownertrust_start; gpgme_op_random_bytes; + gpgme_op_random_value; local: *; |