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