* Makefile.in (DLL_OFILES): Add arc4random.o.
* common.din: Export arc4random, arc4random_addrandom, arc4random_buf, arc4random_stir and arc4random_uniform. * mktemp.cc (arc4random): Remove static replacement function. * posix.sgml (std-bsd): Add arc4random functions. * include/cygwin/stdlib.h: Declare arc4random functions. * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump. * libc/arc4random.cc: New file implementing arc4random functions taken from FreeBSD.
This commit is contained in:
		
							
								
								
									
										363
									
								
								winsup/cygwin/libc/arc4random.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								winsup/cygwin/libc/arc4random.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,363 @@ | ||||
| /*	$OpenBSD: arc4random.c,v 1.22 2010/12/22 08:23:42 otto Exp $	*/ | ||||
|  | ||||
| /* | ||||
|  * Copyright (c) 1996, David Mazieres <dm@uun.org> | ||||
|  * Copyright (c) 2008, Damien Miller <djm@openbsd.org> | ||||
|  * | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Arc4 random number generator for OpenBSD. | ||||
|  * | ||||
|  * This code is derived from section 17.1 of Applied Cryptography, | ||||
|  * second edition, which describes a stream cipher allegedly | ||||
|  * compatible with RSA Labs "RC4" cipher (the actual description of | ||||
|  * which is a trade secret).  The same algorithm is used as a stream | ||||
|  * cipher called "arcfour" in Tatu Ylonen's ssh package. | ||||
|  * | ||||
|  * RC4 is a registered trademark of RSA Laboratories. | ||||
|  */ | ||||
|  | ||||
| #include <sys/cdefs.h> | ||||
| __FBSDID("$FreeBSD: src/lib/libc/gen/arc4random.c,v 1.30 2012/11/17 01:49:23 svnexp Exp $"); | ||||
|  | ||||
| #ifdef __CYGWIN__ | ||||
| #include "winsup.h" | ||||
| #include "sync.h" | ||||
| #else | ||||
| #include "namespace.h" | ||||
| #endif | ||||
| #include <fcntl.h> | ||||
| #include <limits.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/param.h> | ||||
| #ifndef __CYGWIN__ | ||||
| #include <sys/sysctl.h> | ||||
| #endif | ||||
| #include <sys/time.h> | ||||
| #include <pthread.h> | ||||
|  | ||||
| #ifndef __CYGWIN__ | ||||
| #include "libc_private.h" | ||||
| #include "un-namespace.h" | ||||
| #endif | ||||
|  | ||||
| #ifdef __CYGWIN__ | ||||
| #define _open open | ||||
| #define _read read | ||||
| #define _close close | ||||
| #endif | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| #define inline __inline | ||||
| #else				/* !__GNUC__ */ | ||||
| #define inline | ||||
| #endif				/* !__GNUC__ */ | ||||
|  | ||||
| struct arc4_stream { | ||||
| 	u_int8_t i; | ||||
| 	u_int8_t j; | ||||
| 	u_int8_t s[256]; | ||||
| }; | ||||
|  | ||||
| #ifdef __CYGWIN__ | ||||
| static NO_COPY muto arc4random_mtx; | ||||
| #else | ||||
| static pthread_mutex_t	arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; | ||||
| #endif | ||||
|  | ||||
| #define	RANDOMDEV	"/dev/random" | ||||
| #define	KEYSIZE		128 | ||||
| #ifdef __CYGWIN__ | ||||
| #define _ARC4_LOCK()						\ | ||||
| 	do {							\ | ||||
| 		if (__isthreaded)				\ | ||||
| 			arc4random_mtx.init ("arc4random_mtx")->acquire (); \ | ||||
| 	} while (0) | ||||
| #define _ARC4_UNLOCK()						\ | ||||
| 	do {							\ | ||||
| 		if (__isthreaded)				\ | ||||
| 			arc4random_mtx.release ();		\ | ||||
| 	} while (0) | ||||
| #else | ||||
| #define	_ARC4_LOCK()						\ | ||||
| 	do {							\ | ||||
| 		if (__isthreaded)				\ | ||||
| 			_pthread_mutex_lock(&arc4random_mtx);	\ | ||||
| 	} while (0) | ||||
|  | ||||
| #define	_ARC4_UNLOCK()						\ | ||||
| 	do {							\ | ||||
| 		if (__isthreaded)				\ | ||||
| 			_pthread_mutex_unlock(&arc4random_mtx);	\ | ||||
| 	} while (0) | ||||
| #endif | ||||
|  | ||||
| static int rs_initialized; | ||||
| static struct arc4_stream rs; | ||||
| static pid_t arc4_stir_pid; | ||||
| static int arc4_count; | ||||
|  | ||||
| #ifndef __CYGWIN__ | ||||
| extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, | ||||
|     void *newp, size_t newlen); | ||||
| #endif | ||||
|  | ||||
| static inline u_int8_t arc4_getbyte(void); | ||||
| static void arc4_stir(void); | ||||
|  | ||||
| static inline void | ||||
| arc4_init(void) | ||||
| { | ||||
| 	int     n; | ||||
|  | ||||
| 	for (n = 0; n < 256; n++) | ||||
| 		rs.s[n] = n; | ||||
| 	rs.i = 0; | ||||
| 	rs.j = 0; | ||||
| } | ||||
|  | ||||
| static inline void | ||||
| arc4_addrandom(u_char *dat, int datlen) | ||||
| { | ||||
| 	int     n; | ||||
| 	u_int8_t si; | ||||
|  | ||||
| 	rs.i--; | ||||
| 	for (n = 0; n < 256; n++) { | ||||
| 		rs.i = (rs.i + 1); | ||||
| 		si = rs.s[rs.i]; | ||||
| 		rs.j = (rs.j + si + dat[n % datlen]); | ||||
| 		rs.s[rs.i] = rs.s[rs.j]; | ||||
| 		rs.s[rs.j] = si; | ||||
| 	} | ||||
| 	rs.j = rs.i; | ||||
| } | ||||
|  | ||||
| #ifndef __CYGWIN__ | ||||
| static size_t | ||||
| arc4_sysctl(u_char *buf, size_t size) | ||||
| { | ||||
| 	int mib[2]; | ||||
| 	size_t len, done; | ||||
|  | ||||
| 	mib[0] = CTL_KERN; | ||||
| 	mib[1] = KERN_ARND; | ||||
| 	done = 0; | ||||
|  | ||||
| 	do { | ||||
| 		len = size; | ||||
| 		if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) | ||||
| 			return (done); | ||||
| 		done += len; | ||||
| 		buf += len; | ||||
| 		size -= len; | ||||
| 	} while (size > 0); | ||||
|  | ||||
| 	return (done); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static void | ||||
| arc4_stir(void) | ||||
| { | ||||
| 	int done, fd, i; | ||||
| 	struct { | ||||
| 		struct timeval	tv; | ||||
| 		pid_t		pid; | ||||
| 		u_char	 	rnd[KEYSIZE]; | ||||
| 	} rdat; | ||||
|  | ||||
| 	if (!rs_initialized) { | ||||
| 		arc4_init(); | ||||
| 		rs_initialized = 1; | ||||
| 	} | ||||
| 	done = 0; | ||||
| #ifndef __CYGWIN__ | ||||
| 	if (arc4_sysctl((u_char *)&rdat, KEYSIZE) == KEYSIZE) | ||||
| 		done = 1; | ||||
| #endif | ||||
| 	if (!done) { | ||||
| 		fd = _open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0); | ||||
| 		if (fd >= 0) { | ||||
| 			if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) | ||||
| 				done = 1; | ||||
| 			(void)_close(fd); | ||||
| 		} | ||||
| 	} | ||||
| 	if (!done) { | ||||
| 		(void)gettimeofday(&rdat.tv, NULL); | ||||
| 		rdat.pid = getpid(); | ||||
| 		/* We'll just take whatever was on the stack too... */ | ||||
| 	} | ||||
|  | ||||
| 	arc4_addrandom((u_char *)&rdat, KEYSIZE); | ||||
|  | ||||
| 	/* | ||||
| 	 * Discard early keystream, as per recommendations in: | ||||
| 	 * "(Not So) Random Shuffles of RC4" by Ilya Mironov. | ||||
| 	 */ | ||||
| 	for (i = 0; i < 1024; i++) | ||||
| 		(void)arc4_getbyte(); | ||||
| 	arc4_count = 1600000; | ||||
| } | ||||
|  | ||||
| static void | ||||
| arc4_stir_if_needed(void) | ||||
| { | ||||
| 	pid_t pid = getpid(); | ||||
|  | ||||
| 	if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) | ||||
| 	{ | ||||
| 		arc4_stir_pid = pid; | ||||
| 		arc4_stir(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static inline u_int8_t | ||||
| arc4_getbyte(void) | ||||
| { | ||||
| 	u_int8_t si, sj; | ||||
|  | ||||
| 	rs.i = (rs.i + 1); | ||||
| 	si = rs.s[rs.i]; | ||||
| 	rs.j = (rs.j + si); | ||||
| 	sj = rs.s[rs.j]; | ||||
| 	rs.s[rs.i] = sj; | ||||
| 	rs.s[rs.j] = si; | ||||
| 	return (rs.s[(si + sj) & 0xff]); | ||||
| } | ||||
|  | ||||
| static inline u_int32_t | ||||
| arc4_getword(void) | ||||
| { | ||||
| 	u_int32_t val; | ||||
| 	val = arc4_getbyte() << 24; | ||||
| 	val |= arc4_getbyte() << 16; | ||||
| 	val |= arc4_getbyte() << 8; | ||||
| 	val |= arc4_getbyte(); | ||||
| 	return val; | ||||
| } | ||||
|  | ||||
| void | ||||
| arc4random_stir(void) | ||||
| { | ||||
| 	_ARC4_LOCK(); | ||||
| 	arc4_stir(); | ||||
| 	_ARC4_UNLOCK(); | ||||
| } | ||||
|  | ||||
| void | ||||
| arc4random_addrandom(u_char *dat, int datlen) | ||||
| { | ||||
| 	_ARC4_LOCK(); | ||||
| 	if (!rs_initialized) | ||||
| 		arc4_stir(); | ||||
| 	arc4_addrandom(dat, datlen); | ||||
| 	_ARC4_UNLOCK(); | ||||
| } | ||||
|  | ||||
| u_int32_t | ||||
| arc4random(void) | ||||
| { | ||||
| 	u_int32_t val; | ||||
| 	_ARC4_LOCK(); | ||||
| 	arc4_count -= 4; | ||||
| 	arc4_stir_if_needed(); | ||||
| 	val = arc4_getword(); | ||||
| 	_ARC4_UNLOCK(); | ||||
| 	return val; | ||||
| } | ||||
|  | ||||
| void | ||||
| arc4random_buf(void *_buf, size_t n) | ||||
| { | ||||
| 	u_char *buf = (u_char *)_buf; | ||||
| 	_ARC4_LOCK(); | ||||
| 	arc4_stir_if_needed(); | ||||
| 	while (n--) { | ||||
| 		if (--arc4_count <= 0) | ||||
| 			arc4_stir(); | ||||
| 		buf[n] = arc4_getbyte(); | ||||
| 	} | ||||
| 	_ARC4_UNLOCK(); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Calculate a uniformly distributed random number less than upper_bound | ||||
|  * avoiding "modulo bias". | ||||
|  * | ||||
|  * Uniformity is achieved by generating new random numbers until the one | ||||
|  * returned is outside the range [0, 2**32 % upper_bound).  This | ||||
|  * guarantees the selected random number will be inside | ||||
|  * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) | ||||
|  * after reduction modulo upper_bound. | ||||
|  */ | ||||
| u_int32_t | ||||
| arc4random_uniform(u_int32_t upper_bound) | ||||
| { | ||||
| 	u_int32_t r, min; | ||||
|  | ||||
| 	if (upper_bound < 2) | ||||
| 		return 0; | ||||
|  | ||||
| #if (ULONG_MAX > 0xffffffffUL) | ||||
| 	min = 0x100000000UL % upper_bound; | ||||
| #else | ||||
| 	/* Calculate (2**32 % upper_bound) avoiding 64-bit math */ | ||||
| 	if (upper_bound > 0x80000000) | ||||
| 		min = 1 + ~upper_bound;		/* 2**32 - upper_bound */ | ||||
| 	else { | ||||
| 		/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ | ||||
| 		min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	/* | ||||
| 	 * This could theoretically loop forever but each retry has | ||||
| 	 * p > 0.5 (worst case, usually far better) of selecting a | ||||
| 	 * number inside the range we need, so it should rarely need | ||||
| 	 * to re-roll. | ||||
| 	 */ | ||||
| 	for (;;) { | ||||
| 		r = arc4random(); | ||||
| 		if (r >= min) | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	return r % upper_bound; | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| /*-------- Test code for i386 --------*/ | ||||
| #include <stdio.h> | ||||
| #include <machine/pctr.h> | ||||
| int | ||||
| main(int argc, char **argv) | ||||
| { | ||||
| 	const int iter = 1000000; | ||||
| 	int     i; | ||||
| 	pctrval v; | ||||
|  | ||||
| 	v = rdtsc(); | ||||
| 	for (i = 0; i < iter; i++) | ||||
| 		arc4random(); | ||||
| 	v = rdtsc() - v; | ||||
| 	v /= iter; | ||||
|  | ||||
| 	printf("%qd cycles\n", v); | ||||
| } | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user