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
This commit is contained in:
parent
7568566ef3
commit
926b1f1f1e
8
NEWS
8
NEWS
@ -1,8 +1,11 @@
|
|||||||
Noteworthy changes in version 2.0.0 (unreleased)
|
Noteworthy changes in version 2.0.0 (unreleased)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
* New function gpgme_op_random_bytes to get cryptographically strng
|
* New function gpgme_op_random_bytes to get cryptographically
|
||||||
random bytes from gpg.
|
strong random bytes from gpg. [T6694]
|
||||||
|
|
||||||
|
* New function gpgme_op_random_value to get a cryptographically
|
||||||
|
strong unsigned integer random value. [T6694]
|
||||||
|
|
||||||
* Removed the gpgme_attr_t enums and their functions which were
|
* Removed the gpgme_attr_t enums and their functions which were
|
||||||
deprecated since 2003. [rMd54d6eaa64]
|
deprecated since 2003. [rMd54d6eaa64]
|
||||||
@ -16,6 +19,7 @@ Noteworthy changes in version 2.0.0 (unreleased)
|
|||||||
* Interface changes relative to the 1.24 branch:
|
* Interface changes relative to the 1.24 branch:
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
gpgme_op_random_bytes NEW.
|
gpgme_op_random_bytes NEW.
|
||||||
|
gpgme_op_random_value NEW.
|
||||||
GPGME_RANDOM_MODE_NORMAL NEW.
|
GPGME_RANDOM_MODE_NORMAL NEW.
|
||||||
GPGME_RANDOM_MODE_ZBASE32 NEW.
|
GPGME_RANDOM_MODE_ZBASE32 NEW.
|
||||||
gpgme_attr_t REMOVED.
|
gpgme_attr_t REMOVED.
|
||||||
|
@ -7142,11 +7142,26 @@ The function @code{gpgme_op_random_bytes} returns random bytes.
|
|||||||
from gpg. However, if @var{mode} is @code{GPGME_RANDOM_MODE_ZBASE32}
|
from gpg. However, if @var{mode} is @code{GPGME_RANDOM_MODE_ZBASE32}
|
||||||
@var{bufsize} needs to be at least 31 and will be filled with a string
|
@var{bufsize} needs to be at least 31 and will be filled with a string
|
||||||
of 30 ASCII characters followed by a Nul; the remainder of the buffer
|
of 30 ASCII characters followed by a Nul; the remainder of the buffer
|
||||||
is not changed. This function has a limit of 1024 bytes to avoid
|
is not changed. The caller must provide a context @var{ctx}
|
||||||
accidental overuse of the random generator
|
initialized for GPGME_PROTOCOL_OPENPGP. This function has a limit of
|
||||||
|
1024 bytes to avoid accidental overuse of the random generator
|
||||||
|
|
||||||
@end deftypefun
|
@end deftypefun
|
||||||
|
|
||||||
|
@deftypefun {gpgme_error_t} gpgme_op_random_values ( @
|
||||||
|
@w{gpgme_ctx_t @var{ctx}}, @
|
||||||
|
@w{size_t @var{limit}}, @
|
||||||
|
@w{size_t *@var{retval}})
|
||||||
|
|
||||||
|
@since{2.0.0}
|
||||||
|
|
||||||
|
The function @code{gpgme_op_random_value} returns an unbiased random
|
||||||
|
value in the range 0 <= value < @var{limit}. The value is returned at
|
||||||
|
@var{retval} if and only if the function returns with success. The
|
||||||
|
caller must also provide a context @var{ctx} initialized for
|
||||||
|
GPGME_PROTOCOL_OPENPGP.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@node Miscellaneous
|
@node Miscellaneous
|
||||||
|
@ -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.
|
/* Fill BUFFER of size BUFSIZE with random bytes retrieved from gpg.
|
||||||
* If GPGME_RANDOM_MODE_ZBASE32 is used BUFSIZE needs to be at least
|
* 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
|
* 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);
|
gpgme_data_release (data);
|
||||||
return TRACE_ERR (err);
|
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);
|
||||||
|
}
|
||||||
|
@ -276,4 +276,5 @@ EXPORTS
|
|||||||
gpgme_op_setownertrust_start @214
|
gpgme_op_setownertrust_start @214
|
||||||
|
|
||||||
gpgme_op_random_bytes @215
|
gpgme_op_random_bytes @215
|
||||||
|
gpgme_op_random_value @216
|
||||||
; END
|
; END
|
||||||
|
@ -2481,10 +2481,15 @@ typedef enum
|
|||||||
}
|
}
|
||||||
gpgme_random_mode_t;
|
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,
|
gpgme_error_t gpgme_op_random_bytes (gpgme_ctx_t ctx, gpgme_random_mode_t mode,
|
||||||
char *buffer, size_t bufsize);
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -274,6 +274,7 @@ GPGME_1.0 {
|
|||||||
gpgme_op_setownertrust_start;
|
gpgme_op_setownertrust_start;
|
||||||
|
|
||||||
gpgme_op_random_bytes;
|
gpgme_op_random_bytes;
|
||||||
|
gpgme_op_random_value;
|
||||||
|
|
||||||
local:
|
local:
|
||||||
*;
|
*;
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <gpgme.h>
|
#include <gpgme.h>
|
||||||
|
|
||||||
@ -42,10 +44,13 @@ static int verbose;
|
|||||||
static int
|
static int
|
||||||
show_usage (int ex)
|
show_usage (int ex)
|
||||||
{
|
{
|
||||||
fputs ("usage: " PGM " [options]\n\n"
|
fputs ("usage: " PGM " [options] [LIMIT]\n\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" --verbose run in verbose mode\n"
|
" --verbose run in verbose mode\n"
|
||||||
" --zbase32 generate 30 zbase32 characters\n"
|
" --zbase32 generate 30 zbase32 characters\n"
|
||||||
|
" --hex return a hex value in LIMIT mode\n"
|
||||||
|
"\n"
|
||||||
|
"With LIMIT return a decimal value in the range [0,LIMIT)\n"
|
||||||
, stderr);
|
, stderr);
|
||||||
exit (ex);
|
exit (ex);
|
||||||
}
|
}
|
||||||
@ -60,6 +65,8 @@ main (int argc, char **argv)
|
|||||||
gpgme_protocol_t protocol = GPGME_PROTOCOL_OPENPGP;
|
gpgme_protocol_t protocol = GPGME_PROTOCOL_OPENPGP;
|
||||||
gpgme_random_mode_t mode = 0;
|
gpgme_random_mode_t mode = 0;
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
|
int hexmode = 0;
|
||||||
|
int valuemode = 0;
|
||||||
|
|
||||||
|
|
||||||
if (argc)
|
if (argc)
|
||||||
@ -85,11 +92,21 @@ main (int argc, char **argv)
|
|||||||
mode = GPGME_RANDOM_MODE_ZBASE32;
|
mode = GPGME_RANDOM_MODE_ZBASE32;
|
||||||
argc--; argv++;
|
argc--; argv++;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (*argv, "--hex"))
|
||||||
|
{
|
||||||
|
hexmode = 1;
|
||||||
|
argc--; argv++;
|
||||||
|
}
|
||||||
else if (!strncmp (*argv, "--", 2))
|
else if (!strncmp (*argv, "--", 2))
|
||||||
show_usage (1);
|
show_usage (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc)
|
if (argc == 1)
|
||||||
|
valuemode = 1;
|
||||||
|
else if (argc)
|
||||||
|
show_usage (1);
|
||||||
|
|
||||||
|
if ((valuemode && mode) || (!valuemode && hexmode))
|
||||||
show_usage (1);
|
show_usage (1);
|
||||||
|
|
||||||
init_gpgme (protocol);
|
init_gpgme (protocol);
|
||||||
@ -98,26 +115,62 @@ main (int argc, char **argv)
|
|||||||
fail_if_err (err);
|
fail_if_err (err);
|
||||||
gpgme_set_protocol (ctx, protocol);
|
gpgme_set_protocol (ctx, protocol);
|
||||||
|
|
||||||
err = gpgme_op_random_bytes (ctx, mode, buffer, sizeof buffer);
|
if (valuemode)
|
||||||
if (err)
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, PGM ": error getting random: %s\n", gpg_strerror (err));
|
size_t limit, value;
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == GPGME_RANDOM_MODE_ZBASE32)
|
errno = 0;
|
||||||
puts (buffer);
|
limit = strtoul (*argv, NULL, 0);
|
||||||
|
if (errno)
|
||||||
|
{
|
||||||
|
fprintf (stderr, PGM ": error parsing LIMIT arg: %s\n",
|
||||||
|
strerror (errno));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
if (limit > SIZE_MAX)
|
||||||
|
{
|
||||||
|
fprintf (stderr, PGM ": error parsing LIMIT arg: %s\n",
|
||||||
|
"too large for size_t");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gpgme_op_random_value (ctx, limit, &value);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
fprintf (stderr, PGM ": error getting random: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hexmode)
|
||||||
|
printf ("%zx\n", value);
|
||||||
|
else
|
||||||
|
printf ("%zu\n", value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i;
|
err = gpgme_op_random_bytes (ctx, mode, buffer, sizeof buffer);
|
||||||
|
if (err)
|
||||||
for (i=0; i < sizeof buffer; i++)
|
|
||||||
{
|
{
|
||||||
if (i && !(i%32))
|
fprintf (stderr, PGM ": error getting random: %s\n",
|
||||||
putchar ('\n');
|
gpg_strerror (err));
|
||||||
printf ("%02x", ((unsigned char *)buffer)[i]);
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == GPGME_RANDOM_MODE_ZBASE32)
|
||||||
|
puts (buffer);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i < sizeof buffer; i++)
|
||||||
|
{
|
||||||
|
if (i && !(i%32))
|
||||||
|
putchar ('\n');
|
||||||
|
printf ("%02x", ((unsigned char *)buffer)[i]);
|
||||||
|
}
|
||||||
|
putchar ('\n');
|
||||||
}
|
}
|
||||||
putchar ('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gpgme_release (ctx);
|
gpgme_release (ctx);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user