1*67b9b338Schristos /* $NetBSD: ldseed.c,v 1.2 2022/10/08 16:12:50 christos Exp $ */
24a672054Schristos
34a672054Schristos /*++
44a672054Schristos /* NAME
54a672054Schristos /* ldseed 3
64a672054Schristos /* SUMMARY
74a672054Schristos /* seed for non-cryptographic applications
84a672054Schristos /* SYNOPSIS
94a672054Schristos /* #include <ldseed.h>
104a672054Schristos /*
114a672054Schristos /* void ldseed(
124a672054Schristos /* void *dst,
134a672054Schristos /* size_t len)
144a672054Schristos /* DESCRIPTION
154a672054Schristos /* ldseed() preferably extracts pseudo-random bits from
164a672054Schristos /* /dev/urandom, a non-blocking device that is available on
174a672054Schristos /* modern systems.
184a672054Schristos /*
194a672054Schristos /* On systems where /dev/urandom is unavailable or does not
204a672054Schristos /* immediately return the requested amount of randomness,
214a672054Schristos /* ldseed() falls back to a combination of wallclock time,
224a672054Schristos /* the time since boot, and the process ID.
234a672054Schristos /* BUGS
244a672054Schristos /* With Linux "the O_NONBLOCK flag has no effect when opening
254a672054Schristos /* /dev/urandom", but reads "can incur an appreciable delay
264a672054Schristos /* when requesting large amounts of data". Apparently, "large"
274a672054Schristos /* means more than 256 bytes.
284a672054Schristos /* LICENSE
294a672054Schristos /* .ad
304a672054Schristos /* .fi
314a672054Schristos /* The Secure Mailer license must be distributed with this software.
324a672054Schristos /* AUTHOR(S)
334a672054Schristos /* Wietse Venema
344a672054Schristos /* Google, Inc.
354a672054Schristos /* 111 8th Avenue
364a672054Schristos /* New York, NY 10011, USA
374a672054Schristos /*--*/
384a672054Schristos
394a672054Schristos /*
404a672054Schristos * System library
414a672054Schristos */
424a672054Schristos #include <sys_defs.h>
434a672054Schristos #include <string.h>
444a672054Schristos #include <sys/time.h>
454a672054Schristos #include <time.h>
464a672054Schristos #include <stdlib.h>
474a672054Schristos #include <fcntl.h>
484a672054Schristos #include <unistd.h>
494a672054Schristos #include <limits.h> /* CHAR_BIT */
504a672054Schristos
514a672054Schristos /*
524a672054Schristos * Utility library.
534a672054Schristos */
544a672054Schristos #include <iostuff.h>
554a672054Schristos #include <msg.h>
564a672054Schristos #include <ldseed.h>
574a672054Schristos
584a672054Schristos /*
594a672054Schristos * Different systems have different names for non-wallclock time.
604a672054Schristos */
614a672054Schristos #ifdef CLOCK_UPTIME
624a672054Schristos #define NON_WALLTIME_CLOCK CLOCK_UPTIME
634a672054Schristos #elif defined(CLOCK_BOOTTIME)
644a672054Schristos #define NON_WALLTIME_CLOCK CLOCK_BOOTTIME
654a672054Schristos #elif defined(CLOCK_MONOTONIC)
664a672054Schristos #define NON_WALLTIME_CLOCK CLOCK_MONOTONIC
674a672054Schristos #elif defined(CLOCK_HIGHRES)
684a672054Schristos #define NON_WALLTIME_CLOCK CLOCK_HIGHRES
694a672054Schristos #endif
704a672054Schristos
714a672054Schristos /* ldseed - best-effort, low-dependency seed */
724a672054Schristos
ldseed(void * dst,size_t len)734a672054Schristos void ldseed(void *dst, size_t len)
744a672054Schristos {
754a672054Schristos int count;
764a672054Schristos int fd;
774a672054Schristos int n;
784a672054Schristos time_t fallback = 0;
794a672054Schristos
804a672054Schristos /*
814a672054Schristos * Medium-quality seed.
824a672054Schristos */
834a672054Schristos if ((fd = open("/dev/urandom", O_RDONLY)) > 0) {
844a672054Schristos non_blocking(fd, NON_BLOCKING);
854a672054Schristos count = read(fd, dst, len);
864a672054Schristos (void) close(fd);
874a672054Schristos if (count == len)
884a672054Schristos return;
894a672054Schristos }
904a672054Schristos
914a672054Schristos /*
924a672054Schristos * Low-quality seed. Based on 1) the time since boot (good when an
934a672054Schristos * attacker knows the program start time but not the system boot time),
944a672054Schristos * and 2) absolute time (good when an attacker does not know the program
954a672054Schristos * start time). Assumes a system with better than microsecond resolution,
964a672054Schristos * and a network stack that does not leak the time since boot, for
974a672054Schristos * example, through TCP or ICMP timestamps. With those caveats, this seed
984a672054Schristos * is good for 20-30 bits of randomness.
994a672054Schristos */
1004a672054Schristos #ifdef NON_WALLTIME_CLOCK
1014a672054Schristos {
1024a672054Schristos struct timespec ts;
1034a672054Schristos
1044a672054Schristos if (clock_gettime(NON_WALLTIME_CLOCK, &ts) != 0)
1054a672054Schristos msg_fatal("clock_gettime() failed: %m");
1064a672054Schristos fallback += ts.tv_sec ^ ts.tv_nsec;
1074a672054Schristos }
1084a672054Schristos #elif defined(USE_GETHRTIME)
1094a672054Schristos fallback += gethrtime();
1104a672054Schristos #endif
1114a672054Schristos
1124a672054Schristos #ifdef CLOCK_REALTIME
1134a672054Schristos {
1144a672054Schristos struct timespec ts;
1154a672054Schristos
1164a672054Schristos if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
1174a672054Schristos msg_fatal("clock_gettime() failed: %m");
1184a672054Schristos fallback += ts.tv_sec ^ ts.tv_nsec;
1194a672054Schristos }
1204a672054Schristos #else
1214a672054Schristos {
1224a672054Schristos struct timeval tv;
1234a672054Schristos
1244a672054Schristos if (GETTIMEOFDAY(&tv) != 0)
1254a672054Schristos msg_fatal("gettimeofday() failed: %m");
1264a672054Schristos fallback += tv.tv_sec + tv.tv_usec;
1274a672054Schristos }
1284a672054Schristos #endif
1294a672054Schristos fallback += getpid();
1304a672054Schristos
1314a672054Schristos /*
1324a672054Schristos * Copy the least significant bytes first, because those are the most
1334a672054Schristos * volatile.
1344a672054Schristos */
1354a672054Schristos for (n = 0; n < sizeof(fallback) && n < len; n++) {
1364a672054Schristos *(char *) dst++ ^= (fallback & 0xff);
1374a672054Schristos fallback >>= CHAR_BIT;
1384a672054Schristos }
1394a672054Schristos return;
1404a672054Schristos }
141