xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/ldseed.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
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