archive_random.c revision 313570
1153761Swollman/*-
2226976Sedwin * Copyright (c) 2014 Michihiro NAKAJIMA
3192886Sedwin * All rights reserved.
4192886Sedwin *
5153761Swollman * Redistribution and use in source and binary forms, with or without
62742Swollman * modification, are permitted provided that the following conditions
786464Swollman * are met:
82742Swollman * 1. Redistributions of source code must retain the above copyright
92742Swollman *    notice, this list of conditions and the following disclaimer.
102742Swollman * 2. Redistributions in binary form must reproduce the above copyright
112742Swollman *    notice, this list of conditions and the following disclaimer in the
122742Swollman *    documentation and/or other materials provided with the distribution.
132742Swollman *
1486222Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1586222Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
162742Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1758787Sru * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
182742Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
192742Swollman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
202742Swollman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
212742Swollman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
222742Swollman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
232742Swollman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2458787Sru */
2558787Sru
2658787Sru#include "archive_platform.h"
272742Swollman__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive/archive_random.c 313570 2017-02-11 00:54:16Z mm $");
282742Swollman
299908Swollman#ifdef HAVE_STDLIB_H
302742Swollman#include <stdlib.h>
3130711Swollman#endif
322742Swollman
339908Swollman#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
34169811Swollman
35169811Swollman#ifdef HAVE_FCNTL
36169811Swollman#include <fcntl.h>
37169811Swollman#endif
38169811Swollman#ifdef HAVE_LIMITS_H
39169811Swollman#include <limits.h>
40169811Swollman#endif
41169811Swollman#ifdef HAVE_UNISTD_H
42169811Swollman#include <unistd.h>
43169811Swollman#endif
44169811Swollman#ifdef HAVE_SYS_TYPES_H
452742Swollman#include <sys/types.h>
4658787Sru#endif
47169811Swollman#ifdef HAVE_SYS_TIME_H
48169811Swollman#include <sys/time.h>
49169811Swollman#endif
50169811Swollman#ifdef HAVE_PTHREAD_H
51169811Swollman#include <pthread.h>
529908Swollman#endif
5320094Swollman
54149514Swollmanstatic void arc4random_buf(void *, size_t);
5520094Swollman
5620094Swollman#endif /* HAVE_ARC4RANDOM_BUF */
5720094Swollman
5820094Swollman#include "archive.h"
5920094Swollman#include "archive_random_private.h"
6020094Swollman
6120094Swollman#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
6220094Swollman#include <wincrypt.h>
6320094Swollman#endif
6420094Swollman
6520094Swollman#ifndef O_CLOEXEC
6658787Sru#define O_CLOEXEC	0
6758787Sru#endif
6821217Swollman
6921217Swollman/*
7058787Sru * Random number generator function.
7158787Sru * This simply calls arc4random_buf function if the platform provides it.
722742Swollman */
7358787Sru
7421217Swollmanint
7520094Swollmanarchive_random(void *buf, size_t nbytes)
7658787Sru{
7758787Sru#if defined(_WIN32) && !defined(__CYGWIN__)
7820094Swollman	HCRYPTPROV hProv;
792742Swollman	BOOL success;
809908Swollman
812742Swollman	success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
8214343Swollman	    CRYPT_VERIFYCONTEXT);
8314343Swollman	if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) {
84171948Sedwin		success = CryptAcquireContext(&hProv, NULL, NULL,
8514343Swollman		    PROV_RSA_FULL, CRYPT_NEWKEYSET);
8614343Swollman	}
87218122Sedwin	if (success) {
88218122Sedwin		success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf);
89218122Sedwin		CryptReleaseContext(hProv, 0);
90218122Sedwin		if (success)
91218122Sedwin			return ARCHIVE_OK;
92149514Swollman	}
93218122Sedwin	/* TODO: Does this case really happen? */
94171948Sedwin	return ARCHIVE_FAILED;
95171948Sedwin#else
96171948Sedwin	arc4random_buf(buf, nbytes);
972742Swollman	return ARCHIVE_OK;
982742Swollman#endif
992742Swollman}
10058787Sru
1012742Swollman#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
1022742Swollman
1039908Swollman/*	$OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $	*/
104149514Swollman/*
105149514Swollman * Copyright (c) 1996, David Mazieres <dm@uun.org>
106149514Swollman * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
107149514Swollman *
108149514Swollman * Permission to use, copy, modify, and distribute this software for any
1092742Swollman * purpose with or without fee is hereby granted, provided that the above
11058787Sru * copyright notice and this permission notice appear in all copies.
11158787Sru *
11214343Swollman * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11314343Swollman * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11458787Sru * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11514343Swollman * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11614343Swollman * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
11714343Swollman * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
11858787Sru * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
11914343Swollman */
12058787Sru
12158787Sru/*
12258787Sru * Arc4 random number generator for OpenBSD.
123149514Swollman *
12458787Sru * This code is derived from section 17.1 of Applied Cryptography,
12558787Sru * second edition, which describes a stream cipher allegedly
126149514Swollman * compatible with RSA Labs "RC4" cipher (the actual description of
127171948Sedwin * which is a trade secret).  The same algorithm is used as a stream
128171948Sedwin * cipher called "arcfour" in Tatu Ylonen's ssh package.
1292742Swollman *
1302742Swollman * RC4 is a registered trademark of RSA Laboratories.
13158787Sru */
13258787Sru
13358787Sru#ifdef __GNUC__
1342742Swollman#define inline __inline
135149514Swollman#else				/* !__GNUC__ */
136149514Swollman#define inline
137149514Swollman#endif				/* !__GNUC__ */
138149514Swollman
139149514Swollmanstruct arc4_stream {
1402742Swollman	uint8_t i;
1419908Swollman	uint8_t j;
1422742Swollman	uint8_t s[256];
14314343Swollman};
14458787Sru
14514343Swollman#define	RANDOMDEV	"/dev/urandom"
14614343Swollman#define	KEYSIZE		128
14758787Sru#ifdef HAVE_PTHREAD_H
14858787Srustatic pthread_mutex_t	arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
14914343Swollman#define	_ARC4_LOCK()	pthread_mutex_lock(&arc4random_mtx);
150149514Swollman#define	_ARC4_UNLOCK()  pthread_mutex_unlock(&arc4random_mtx);
15158787Sru#else
152171948Sedwin#define	_ARC4_LOCK()
153149514Swollman#define	_ARC4_UNLOCK()
154171948Sedwin#endif
155171948Sedwin
156171948Sedwinstatic int rs_initialized;
1572742Swollmanstatic struct arc4_stream rs;
1582742Swollmanstatic pid_t arc4_stir_pid;
15958787Srustatic int arc4_count;
1602742Swollman
1612742Swollmanstatic inline uint8_t arc4_getbyte(void);
1629908Swollmanstatic void arc4_stir(void);
1632742Swollman
16414343Swollmanstatic inline void
16514343Swollmanarc4_init(void)
16614343Swollman{
16714343Swollman	int     n;
16814343Swollman
16914343Swollman	for (n = 0; n < 256; n++)
17014343Swollman		rs.s[n] = n;
17143543Swollman	rs.i = 0;
17214343Swollman	rs.j = 0;
173149514Swollman}
17458787Sru
175171948Sedwinstatic inline void
176149514Swollmanarc4_addrandom(u_char *dat, int datlen)
177171948Sedwin{
178171948Sedwin	int     n;
179171948Sedwin	uint8_t si;
1802742Swollman
1812742Swollman	rs.i--;
18258787Sru	for (n = 0; n < 256; n++) {
1832742Swollman		rs.i = (rs.i + 1);
1842742Swollman		si = rs.s[rs.i];
1852742Swollman		rs.j = (rs.j + si + dat[n % datlen]);
1862742Swollman		rs.s[rs.i] = rs.s[rs.j];
18758787Sru		rs.s[rs.j] = si;
18858787Sru	}
18958787Sru	rs.j = rs.i;
1908029Swollman}
19114343Swollman
19214343Swollmanstatic void
19375267Swollmanarc4_stir(void)
19475267Swollman{
19575267Swollman	int done, fd, i;
19675267Swollman	struct {
19775267Swollman		struct timeval	tv;
19875267Swollman		pid_t		pid;
19975267Swollman		u_char	 	rnd[KEYSIZE];
200149514Swollman	} rdat;
20175267Swollman
202171948Sedwin	if (!rs_initialized) {
203149514Swollman		arc4_init();
204171948Sedwin		rs_initialized = 1;
205171948Sedwin	}
206171948Sedwin	done = 0;
2072742Swollman	fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0);
2082742Swollman	if (fd >= 0) {
20914343Swollman		if (read(fd, &rdat, KEYSIZE) == KEYSIZE)
2108029Swollman			done = 1;
21114343Swollman		(void)close(fd);
2122742Swollman	}
2132742Swollman	if (!done) {
21414343Swollman		(void)gettimeofday(&rdat.tv, NULL);
215169811Swollman		rdat.pid = getpid();
2162742Swollman		/* We'll just take whatever was on the stack too... */
21714343Swollman	}
21814343Swollman
219169811Swollman	arc4_addrandom((u_char *)&rdat, KEYSIZE);
22014343Swollman
22130711Swollman	/*
22230711Swollman	 * Discard early keystream, as per recommendations in:
22358787Sru	 * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
224169811Swollman	 */
2252742Swollman	for (i = 0; i < 1024; i++)
22643014Swollman		(void)arc4_getbyte();
22743014Swollman	arc4_count = 1600000;
22843014Swollman}
22943014Swollman
2302742Swollmanstatic void
2312742Swollmanarc4_stir_if_needed(void)
232158421Swollman{
2332742Swollman	pid_t pid = getpid();
23419878Swollman
23543014Swollman	if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {
23643014Swollman		arc4_stir_pid = pid;
2372742Swollman		arc4_stir();
2382742Swollman	}
23919878Swollman}
24019878Swollman
2412742Swollmanstatic inline uint8_t
2422742Swollmanarc4_getbyte(void)
243149514Swollman{
244149514Swollman	uint8_t si, sj;
2452742Swollman
246149514Swollman	rs.i = (rs.i + 1);
247149514Swollman	si = rs.s[rs.i];
2482742Swollman	rs.j = (rs.j + si);
2492742Swollman	sj = rs.s[rs.j];
250199336Sedwin	rs.s[rs.i] = sj;
251199336Sedwin	rs.s[rs.j] = si;
252199336Sedwin	return (rs.s[(si + sj) & 0xff]);
253199336Sedwin}
254199336Sedwin
255199336Sedwinstatic void
256199336Sedwinarc4random_buf(void *_buf, size_t n)
257199336Sedwin{
258199336Sedwin	u_char *buf = (u_char *)_buf;
259199336Sedwin	_ARC4_LOCK();
260199336Sedwin	arc4_stir_if_needed();
261199336Sedwin	while (n--) {
262199336Sedwin		if (--arc4_count <= 0)
263199336Sedwin			arc4_stir();
264199336Sedwin		buf[n] = arc4_getbyte();
265199336Sedwin	}
266199336Sedwin	_ARC4_UNLOCK();
267199336Sedwin}
268199336Sedwin
269204887Sedwin#endif /* !HAVE_ARC4RANDOM_BUF */
270204887Sedwin