summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2020-01-01 00:00:00 +0100
committerVivien Kraus <vivien@planete-kraus.eu>2021-06-19 13:06:24 +0200
commitb98a6b1c57062e27486950a764589caa195fd60a (patch)
tree48591b28a2bb8a6592d67fae6376876552255361 /src
parentf04df6e51215cf9b43da1fc7fe585d937c6a0479 (diff)
Add a random number generator.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog5
-rw-r--r--src/Makefile.am1
-rw-r--r--src/libwebidoidc.c2
-rw-r--r--src/random/ChangeLog11
-rw-r--r--src/random/Makefile.am20
-rw-r--r--src/random/generate-random.c42
-rw-r--r--src/random/libwebidoidc-random.c35
-rw-r--r--src/random/random.c423
-rw-r--r--src/random/webid-oidc/random.h57
-rw-r--r--src/scm/webid-oidc/stubs.scm4
-rw-r--r--src/scm/webid-oidc/testing.scm1
11 files changed, 600 insertions, 1 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 75ed3d1..e2e9bea 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -3,3 +3,8 @@
* Makefile.am (%canon_reldir%_libwebidoidc_la_SOURCES): the common code is considered a source.
* utilities.h: Put the common code in that header.
+
+ * Makefile.am: build the "random" submodule.
+
+ * libwebidoidc.c (init_webidoidc): Initialize the "random" submodule.
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 93fbada..732a941 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,6 +24,7 @@ install_go_targets = install-webidoidcgoDATA
install_mod_targets = install-webidoidcmodDATA install-dist_webidoidcmodDATA
include %reldir%/base64/Makefile.am
+include %reldir%/random/Makefile.am
include %reldir%/pre-inst/Makefile.am
include %reldir%/inst/Makefile.am
include %reldir%/scm/Makefile.am
diff --git a/src/libwebidoidc.c b/src/libwebidoidc.c
index 09af3fd..af26ae0 100644
--- a/src/libwebidoidc.c
+++ b/src/libwebidoidc.c
@@ -1,9 +1,11 @@
#define N_(s)
void init_webidoidc_base64 (void);
+void init_webidoidc_random (void);
void
init_webidoidc (void)
{
N_("This is the main function.");
init_webidoidc_base64 ();
+ init_webidoidc_random ();
}
diff --git a/src/random/ChangeLog b/src/random/ChangeLog
new file mode 100644
index 0000000..b2a1cc3
--- /dev/null
+++ b/src/random/ChangeLog
@@ -0,0 +1,11 @@
+2020-11-26 Vivien Kraus <vivien@planete-kraus.eu>
+
+ * libwebidoidc-random.c: Fix the submodule to use the package name.
+ (fopen_cache_seed): Fix in this function.
+
+2020-11-25 Vivien Kraus <vivien@planete-kraus.eu>
+
+ * libwebidoidc-random.c: New submodule.
+
+ * generate-random.c: New program.
+
diff --git a/src/random/Makefile.am b/src/random/Makefile.am
new file mode 100644
index 0000000..fbd548c
--- /dev/null
+++ b/src/random/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LTLIBRARIES += %reldir%/libwebidoidc-random.la
+noinst_PROGRAMS += %reldir%/generate-random
+EXTRA_DIST += %reldir%/libwebidoidc-random.x
+BUILT_SOURCES += %reldir%/libwebidoidc-random.x
+include_HEADERS += %reldir%/webid-oidc/random.h
+
+%canon_reldir%_libwebidoidc_random_la_LIBADD = $(GUILE_LIBS) $(NETTLE_LIBS)
+%canon_reldir%_libwebidoidc_random_la_SOURCES = \
+ %reldir%/libwebidoidc-random.c \
+ %reldir%/random.c \
+ %reldir%/webid-oidc/random.h
+%canon_reldir%_generate_random_LDADD = %reldir%/libwebidoidc-random.la $(GUILE_LIBS)
+
+AM_CFLAGS += -I %reldir% -I $(srcdir)/%reldir%
+
+INDENTED += \
+ %reldir%/generate-random.c \
+ $(%canon_reldir%_libwebidoidc_random_la_SOURCES)
+
+%reldir%/libwebidoidc-random.o: %reldir%/libwebidoidc-random.x
diff --git a/src/random/generate-random.c b/src/random/generate-random.c
new file mode 100644
index 0000000..bde01b9
--- /dev/null
+++ b/src/random/generate-random.c
@@ -0,0 +1,42 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libguile.h>
+#include <gettext.h>
+
+#define _(s) gettext (s)
+
+SCM webidoidc_random_g (SCM length);
+
+int init_webidoidc_random (void);
+
+static void
+run (void *params, int argc, char *argv[])
+{
+ size_t n_bytes;
+ char *end;
+ SCM data;
+ (void) params;
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+ if (argc != 2
+ || (n_bytes = strtoull (argv[1], &end, 10)) == 0 || *end != '\0')
+ {
+ fprintf (stderr, _("Usage: generate-random [NUMBER OF BYTES]\n"));
+ exit (1);
+ }
+ init_webidoidc_random ();
+ data = webidoidc_random_g (scm_from_size_t (n_bytes));
+ printf ("%s\n", scm_to_locale_string (data));
+}
+
+int
+main (int argc, char *argv[])
+{
+ scm_boot_guile (argc, argv, run, NULL);
+ return 0;
+}
diff --git a/src/random/libwebidoidc-random.c b/src/random/libwebidoidc-random.c
new file mode 100644
index 0000000..2bea9bb
--- /dev/null
+++ b/src/random/libwebidoidc-random.c
@@ -0,0 +1,35 @@
+#include <utilities.h>
+#include <threads.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <webid-oidc/random.h>
+
+#define _(s) dgettext (PACKAGE, s)
+
+/* Register "random", a guile function to generate random data. */
+void init_webidoidc_random (void);
+
+SCM_DEFINE (webidoidc_random_g, "random", 1, 0, 0, (SCM length),
+ "Get @var{length} random bytes, and encode them in a base64-url string.")
+{
+ size_t c_length = scm_to_size_t (length);
+ uint8_t *data = scm_gc_malloc_pointerless (c_length, "random data");
+ webid_oidc_random (c_length, data);
+ return wrap_bytevector (c_length, data);
+}
+
+SCM_DEFINE (webidoidc_random_init_g, "random-init!", 0, 0, 0, (void),
+ "Re-initialize the random number generator so that future threads are not predictable.")
+{
+ webid_oidc_random_init ();
+ return SCM_UNDEFINED;
+}
+
+void
+init_webidoidc_random (void)
+{
+ webid_oidc_random_init ();
+#ifndef SCM_MAGIC_SNARFER
+#include "libwebidoidc-random.x"
+#endif /* not SCM_MAGIC_SNARFER */
+}
diff --git a/src/random/random.c b/src/random/random.c
new file mode 100644
index 0000000..d5c45f5
--- /dev/null
+++ b/src/random/random.c
@@ -0,0 +1,423 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* not HAVE_CONFIG_H */
+
+#include <string.h>
+#include <nettle/yarrow.h>
+#include <threads.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <webid-oidc/random.h>
+#include <gettext.h>
+#define _(s) dgettext (PACKAGE, s)
+
+struct webid_oidc_random_context
+{
+ struct yarrow256_ctx ctx;
+ enum webid_oidc_random_context_spawn_flags flags;
+ enum webid_oidc_random_context_state state;
+ unsigned int state_progress;
+ uint8_t seed[YARROW256_SEED_FILE_SIZE];
+ mtx_t mutex;
+};
+
+struct webid_oidc_random_context *
+webid_oidc_random_context_alloc (void)
+{
+ struct webid_oidc_random_context *ret =
+ malloc (sizeof (struct webid_oidc_random_context));
+ if (ret && mtx_init (&(ret->mutex), mtx_plain) != thrd_success)
+ {
+ free (ret);
+ ret = NULL;
+ }
+ if (ret)
+ {
+ yarrow256_init (&(ret->ctx), 0, NULL);
+ ret->flags = 0;
+ ret->state = WEBID_OIDC_RANDOM_CONTEXT_WAIT_LOCK_FILE;
+ }
+ return ret;
+}
+
+void
+webid_oidc_random_context_free (struct webid_oidc_random_context *ctx)
+{
+ if (ctx)
+ {
+ mtx_destroy (&(ctx->mutex));
+ }
+ free (ctx);
+}
+
+enum webid_oidc_random_context_state
+webid_oidc_random_context_get_state (const struct webid_oidc_random_context
+ *ctx)
+{
+ return ctx->state;
+}
+
+int
+webid_oidc_random_context_get_wait_bytes (const struct
+ webid_oidc_random_context *ctx,
+ size_t max, size_t start,
+ uint8_t * bytes, size_t *n_bytes)
+{
+ if (ctx->state == WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE)
+ {
+ if (start >= YARROW256_SEED_FILE_SIZE)
+ {
+ *n_bytes = 0;
+ }
+ else
+ {
+ if (max + start > YARROW256_SEED_FILE_SIZE)
+ {
+ max = YARROW256_SEED_FILE_SIZE - start;
+ }
+ memcpy (bytes, ctx->seed + start, max);
+ *n_bytes = YARROW256_SEED_FILE_SIZE - start;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int
+webid_oidc_random_context_ok (struct webid_oidc_random_context *ctx)
+{
+ switch (ctx->state)
+ {
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_LOCK_FILE:
+ ctx->state = WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_READ;
+ ctx->state_progress = 0;
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE:
+ ctx->state = WEBID_OIDC_RANDOM_CONTEXT_WAIT_UNLOCK_FILE;
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_UNLOCK_FILE:
+ ctx->state = WEBID_OIDC_RANDOM_CONTEXT_READY;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int
+webid_oidc_random_context_bytes (struct webid_oidc_random_context *ctx,
+ size_t n_bytes, const uint8_t * bytes)
+{
+ switch (ctx->state)
+ {
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_READ:
+ if (n_bytes >= (YARROW256_SEED_FILE_SIZE - ctx->state_progress))
+ {
+ n_bytes = (YARROW256_SEED_FILE_SIZE - ctx->state_progress);
+ }
+ memcpy (ctx->seed + ctx->state_progress, bytes, n_bytes);
+ ctx->state_progress += n_bytes;
+ if (ctx->state_progress == YARROW256_SEED_FILE_SIZE)
+ {
+ yarrow256_seed (&(ctx->ctx), YARROW256_SEED_FILE_SIZE, ctx->seed);
+ yarrow256_random (&(ctx->ctx), YARROW256_SEED_FILE_SIZE, ctx->seed);
+ ctx->state = WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int
+webid_oidc_random_context_spawn (struct webid_oidc_random_context *parent,
+ struct webid_oidc_random_context *child,
+ enum webid_oidc_random_context_spawn_flags
+ flags)
+{
+ if (!webid_oidc_random_context_get
+ (parent, YARROW256_SEED_FILE_SIZE, child->seed))
+ {
+ return 0;
+ }
+ child->flags = flags;
+ child->state = WEBID_OIDC_RANDOM_CONTEXT_READY;
+ yarrow256_seed (&(child->ctx), YARROW256_SEED_FILE_SIZE, child->seed);
+ return 1;
+}
+
+int
+webid_oidc_random_context_get (struct webid_oidc_random_context *ctx,
+ size_t request_size, uint8_t * data)
+{
+ if (ctx->state == WEBID_OIDC_RANDOM_CONTEXT_READY)
+ {
+ if (!(ctx->flags & WEBID_OIDC_RANDOM_CONTEXT_THREAD_UNSAFE))
+ {
+ if (mtx_lock (&(ctx->mutex)) != thrd_success)
+ {
+ assert (0);
+ }
+ }
+ yarrow256_random (&(ctx->ctx), request_size, data);
+ if (!(ctx->flags & WEBID_OIDC_RANDOM_CONTEXT_THREAD_UNSAFE))
+ {
+ if (mtx_unlock (&(ctx->mutex)) != thrd_success)
+ {
+ assert (0);
+ }
+ }
+ }
+ return (ctx->state == WEBID_OIDC_RANDOM_CONTEXT_READY);
+}
+
+static struct webid_oidc_random_context *global_ctx = NULL;
+
+void
+webid_oidc_random_init (void)
+{
+ char *cache_dir, *pkg_cache_dir, *filename;
+ char *home = getenv ("HOME");
+ char *xdg_cache_home = getenv ("XDG_CACHE_HOME");
+ char *application = getenv ("WEBID_OIDC_APPLICATION_NAME");
+ static const char *default_application = PACKAGE;
+ FILE *seed_file;
+ FILE *system_rng_file;
+ struct flock lock;
+ if (global_ctx)
+ {
+ webid_oidc_random_context_free (global_ctx);
+ global_ctx = NULL;
+ }
+ global_ctx = webid_oidc_random_context_alloc ();
+ if (!global_ctx)
+ {
+ fprintf (stderr, _("Could not set the global random generator up.\n"));
+ abort ();
+ }
+ if (!application)
+ {
+ application = (char *) default_application;
+ }
+ if (xdg_cache_home)
+ {
+ cache_dir = malloc (strlen (xdg_cache_home) + 1);
+ if (!cache_dir)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (cache_dir, xdg_cache_home);
+ }
+ else if (home)
+ {
+ cache_dir = malloc (strlen (home) + strlen ("/.cache") + 1);
+ if (!cache_dir)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (cache_dir, home);
+ strcat (cache_dir, "/.cache");
+ }
+ else
+ {
+ cache_dir = malloc (strlen ("/var/cache") + 1);
+ if (!cache_dir)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (cache_dir, "/var/cache");
+ }
+ pkg_cache_dir = malloc (strlen (cache_dir)
+ + strlen ("/") + strlen (application) + 1);
+ if (!pkg_cache_dir)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (pkg_cache_dir, cache_dir);
+ strcat (pkg_cache_dir, "/");
+ strcat (pkg_cache_dir, application);
+ filename = malloc (strlen (pkg_cache_dir) + strlen ("/seed") + 1);
+ if (!filename)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (filename, pkg_cache_dir);
+ strcat (filename, "/seed");
+ seed_file = fopen (filename, "r+");
+ if (!seed_file)
+ {
+ fprintf (stderr,
+ _
+ ("Warning: could not open the seed file, maybe the parent directory is missing...\n"));
+ if (mkdir (cache_dir, 0777) != 0)
+ {
+ fprintf (stderr,
+ _("Warning: could not create the cache directory '%s'.\n"),
+ cache_dir);
+ perror (_("when creating the cache directory"));
+ }
+ if (mkdir (pkg_cache_dir, 0777) != 0)
+ {
+ fprintf (stderr,
+ _
+ ("Warning: could not create the package cache directory '%s'.\n"),
+ pkg_cache_dir);
+ perror (_("when creating the package cache directory"));
+ }
+ seed_file = fopen (filename, "w+");
+ }
+ if (!seed_file)
+ {
+ fprintf (stderr, _("Could not open the seed file '%s'.\n"), filename);
+ perror (_("when opening the seed file"));
+ abort ();
+ }
+ system_rng_file = fopen ("/dev/random", "r");
+ while (global_ctx->state != WEBID_OIDC_RANDOM_CONTEXT_READY)
+ {
+ int error;
+ int c;
+ uint8_t byte = 0;
+ size_t i, n;
+ switch (global_ctx->state)
+ {
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_LOCK_FILE:
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ error = fcntl (fileno (seed_file), F_SETLKW, &lock);
+ if (error != 0)
+ {
+ fprintf (stderr, _("Could not lock the seed file '%s'.\n"),
+ filename);
+ perror (_("when locking the seed file"));
+ abort ();
+ }
+ if (!webid_oidc_random_context_ok (global_ctx))
+ {
+ assert (0);
+ }
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_READ:
+ c = fgetc (seed_file);
+ if (c == EOF && system_rng_file == NULL)
+ {
+ fprintf (stderr,
+ _
+ ("Warning: the seed file '%s' is too short. This weakens the random number generator. Please write more random data in it.\n"),
+ filename);
+ }
+ else if (c == EOF)
+ {
+ c = fgetc (system_rng_file);
+ }
+ byte = c;
+ if (!webid_oidc_random_context_bytes (global_ctx, 1, &byte))
+ {
+ assert (0);
+ }
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE:
+ if (fseek (seed_file, 0, SEEK_SET) != 0)
+ {
+ fprintf (stderr,
+ _("Could not update the seed file '%s'.\n"), filename);
+ perror (_("when rewinding the seed file"));
+ abort ();
+ }
+ if (!webid_oidc_random_context_get_wait_bytes
+ (global_ctx, 0, 0, NULL, &n))
+ {
+ assert (0);
+ }
+ for (i = 0; i < n; i++)
+ {
+ size_t remaining;
+ if (!webid_oidc_random_context_get_wait_bytes
+ (global_ctx, 1, i, &byte, &remaining))
+ {
+ assert (0);
+ }
+ assert (i + remaining == n);
+ fputc (byte, seed_file);
+ }
+ if (!webid_oidc_random_context_ok (global_ctx))
+ {
+ assert (0);
+ }
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_UNLOCK_FILE:
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ error = fcntl (fileno (seed_file), F_SETLKW, &lock);
+ if (error != 0)
+ {
+ fprintf (stderr, _("Could not unlock the seed file '%s'.\n"),
+ filename);
+ perror (_("when unlocking the seed file"));
+ abort ();
+ }
+ if (!webid_oidc_random_context_ok (global_ctx))
+ {
+ assert (0);
+ }
+ break;
+ default:
+ assert (0);
+ }
+ }
+ fclose (seed_file);
+ fclose (system_rng_file);
+}
+
+void
+webid_oidc_random (size_t request_size, uint8_t * data)
+{
+ static _Thread_local struct webid_oidc_random_context *thrd_ctx = NULL;
+ if (thrd_ctx == NULL)
+ {
+ assert (global_ctx);
+ thrd_ctx = webid_oidc_random_context_alloc ();
+ if (thrd_ctx == NULL)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the thread-local random generator up.\n"));
+ abort ();
+ }
+ if (!webid_oidc_random_context_spawn
+ (global_ctx, thrd_ctx, WEBID_OIDC_RANDOM_CONTEXT_THREAD_UNSAFE))
+ {
+ fprintf (stderr,
+ _
+ ("The random module has not been initialized. Please call webid_oidc_random_init first.\n"));
+ abort ();
+ }
+ }
+ if (!webid_oidc_random_context_get (thrd_ctx, request_size, data))
+ {
+ assert (0);
+ }
+}
diff --git a/src/random/webid-oidc/random.h b/src/random/webid-oidc/random.h
new file mode 100644
index 0000000..ae1adfc
--- /dev/null
+++ b/src/random/webid-oidc/random.h
@@ -0,0 +1,57 @@
+#ifndef H_RANDOM_INCLUDED
+#define H_RANDOM_INCLUDED
+
+struct webid_oidc_random_context;
+typedef struct webid_oidc_random_context webid_oidc_random_context;
+
+/* These functions allocate data, they are not reentrant. */
+struct webid_oidc_random_context *webid_oidc_random_context_alloc (void);
+void webid_oidc_random_context_free (struct webid_oidc_random_context *ctx);
+
+enum webid_oidc_random_context_state
+{
+ WEBID_OIDC_RANDOM_CONTEXT_READY = 0,
+ WEBID_OIDC_RANDOM_CONTEXT_WAIT_LOCK_FILE,
+ WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_READ,
+ WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE,
+ WEBID_OIDC_RANDOM_CONTEXT_WAIT_UNLOCK_FILE
+};
+
+typedef enum webid_oidc_random_context_state webid_oidc_random_context_state;
+
+enum webid_oidc_random_context_state
+webid_oidc_random_context_get_state (const struct webid_oidc_random_context
+ *ctx);
+int webid_oidc_random_context_get_wait_bytes (const struct
+ webid_oidc_random_context *ctx,
+ size_t max, size_t start,
+ uint8_t * bytes,
+ size_t *n_bytes);
+int webid_oidc_random_context_ok (struct webid_oidc_random_context *ctx);
+int webid_oidc_random_context_bytes (struct webid_oidc_random_context *ctx,
+ size_t n_bytes, const uint8_t * bytes);
+
+enum webid_oidc_random_context_spawn_flags
+{
+ WEBID_OIDC_RANDOM_CONTEXT_THREAD_UNSAFE = 1
+};
+typedef enum webid_oidc_random_context_spawn_flags
+ webid_oidc_random_context_spawn_flags;
+
+int webid_oidc_random_context_spawn (struct webid_oidc_random_context *parent,
+ struct webid_oidc_random_context *child,
+ enum
+ webid_oidc_random_context_spawn_flags
+ flags);
+
+int webid_oidc_random_context_get (struct webid_oidc_random_context *ctx,
+ size_t request_size, uint8_t * data);
+
+/* These functions set up and use a global state. Neither are
+ reentrant. */
+void webid_oidc_random_init (void);
+
+/* This function is thread-safe. */
+void webid_oidc_random (size_t request_size, uint8_t * data);
+
+#endif /* not H_RANDOM_INCLUDED */
diff --git a/src/scm/webid-oidc/stubs.scm b/src/scm/webid-oidc/stubs.scm
index 12006e6..b022ef2 100644
--- a/src/scm/webid-oidc/stubs.scm
+++ b/src/scm/webid-oidc/stubs.scm
@@ -15,4 +15,6 @@
(export
base64-encode
- (fix-base64-decode . base64-decode))
+ (fix-base64-decode . base64-decode)
+ random
+ random-init!)
diff --git a/src/scm/webid-oidc/testing.scm b/src/scm/webid-oidc/testing.scm
index 40284cf..d4b7f4d 100644
--- a/src/scm/webid-oidc/testing.scm
+++ b/src/scm/webid-oidc/testing.scm
@@ -24,4 +24,5 @@
(error->str error))
(raise-exception error))
(lambda ()
+ (random-init!)
(f))))