1 /*- 2 * Copyright (c) 2014 Michihiro NAKAJIMA 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "archive_platform.h" 27 __FBSDID("$FreeBSD$"); 28 29 #ifdef HAVE_STDLIB_H 30 #include <stdlib.h> 31 #endif 32 33 #if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__)) 34 35 #ifdef HAVE_FCNTL 36 #include <fcntl.h> 37 #endif 38 #ifdef HAVE_LIMITS_H 39 #include <limits.h> 40 #endif 41 #ifdef HAVE_UNISTD_H 42 #include <unistd.h> 43 #endif 44 #ifdef HAVE_SYS_TYPES_H 45 #include <sys/types.h> 46 #endif 47 #ifdef HAVE_SYS_TIME_H 48 #include <sys/time.h> 49 #endif 50 #ifdef HAVE_PTHREAD_H 51 #include <pthread.h> 52 #endif 53 54 static void la_arc4random_buf(void *, size_t); 55 56 #endif /* HAVE_ARC4RANDOM_BUF */ 57 58 #include "archive.h" 59 #include "archive_random_private.h" 60 61 #if defined(_WIN32) && !defined(__CYGWIN__) 62 #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 63 /* don't use bcrypt when XP needs to be supported */ 64 #include <bcrypt.h> 65 66 /* Common in other bcrypt implementations, but missing from VS2008. */ 67 #ifndef BCRYPT_SUCCESS 68 #define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS) 69 #endif 70 71 #elif defined(HAVE_WINCRYPT_H) 72 #include <wincrypt.h> 73 #endif 74 #endif 75 76 #ifndef O_CLOEXEC 77 #define O_CLOEXEC 0 78 #endif 79 80 /* 81 * Random number generator function. 82 * This simply calls arc4random_buf function if the platform provides it. 83 */ 84 85 int 86 archive_random(void *buf, size_t nbytes) 87 { 88 #if defined(_WIN32) && !defined(__CYGWIN__) 89 # if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 90 NTSTATUS status; 91 BCRYPT_ALG_HANDLE hAlg; 92 93 status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0); 94 if (!BCRYPT_SUCCESS(status)) 95 return ARCHIVE_FAILED; 96 status = BCryptGenRandom(hAlg, buf, nbytes, 0); 97 BCryptCloseAlgorithmProvider(hAlg, 0); 98 if (!BCRYPT_SUCCESS(status)) 99 return ARCHIVE_FAILED; 100 101 return ARCHIVE_OK; 102 # else 103 HCRYPTPROV hProv; 104 BOOL success; 105 106 success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 107 CRYPT_VERIFYCONTEXT); 108 if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) { 109 success = CryptAcquireContext(&hProv, NULL, NULL, 110 PROV_RSA_FULL, CRYPT_NEWKEYSET); 111 } 112 if (success) { 113 success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf); 114 CryptReleaseContext(hProv, 0); 115 if (success) 116 return ARCHIVE_OK; 117 } 118 /* TODO: Does this case really happen? */ 119 return ARCHIVE_FAILED; 120 # endif 121 #elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__)) 122 la_arc4random_buf(buf, nbytes); 123 return ARCHIVE_OK; 124 #else 125 arc4random_buf(buf, nbytes); 126 return ARCHIVE_OK; 127 #endif 128 } 129 130 #if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__)) 131 132 /* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */ 133 /* 134 * Copyright (c) 1996, David Mazieres <dm@uun.org> 135 * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 136 * 137 * Permission to use, copy, modify, and distribute this software for any 138 * purpose with or without fee is hereby granted, provided that the above 139 * copyright notice and this permission notice appear in all copies. 140 * 141 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 142 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 143 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 144 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 145 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 146 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 147 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 148 */ 149 150 /* 151 * Arc4 random number generator for OpenBSD. 152 * 153 * This code is derived from section 17.1 of Applied Cryptography, 154 * second edition, which describes a stream cipher allegedly 155 * compatible with RSA Labs "RC4" cipher (the actual description of 156 * which is a trade secret). The same algorithm is used as a stream 157 * cipher called "arcfour" in Tatu Ylonen's ssh package. 158 * 159 * RC4 is a registered trademark of RSA Laboratories. 160 */ 161 162 #ifdef __GNUC__ 163 #define inline __inline 164 #else /* !__GNUC__ */ 165 #define inline 166 #endif /* !__GNUC__ */ 167 168 struct arc4_stream { 169 uint8_t i; 170 uint8_t j; 171 uint8_t s[256]; 172 }; 173 174 #define RANDOMDEV "/dev/urandom" 175 #define KEYSIZE 128 176 #ifdef HAVE_PTHREAD_H 177 static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; 178 #define _ARC4_LOCK() pthread_mutex_lock(&arc4random_mtx); 179 #define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx); 180 #else 181 #define _ARC4_LOCK() 182 #define _ARC4_UNLOCK() 183 #endif 184 185 static int rs_initialized; 186 static struct arc4_stream rs; 187 static pid_t arc4_stir_pid; 188 static int arc4_count; 189 190 static inline uint8_t arc4_getbyte(void); 191 static void arc4_stir(void); 192 193 static inline void 194 arc4_init(void) 195 { 196 int n; 197 198 for (n = 0; n < 256; n++) 199 rs.s[n] = n; 200 rs.i = 0; 201 rs.j = 0; 202 } 203 204 static inline void 205 arc4_addrandom(uint8_t *dat, int datlen) 206 { 207 int n; 208 uint8_t si; 209 210 rs.i--; 211 for (n = 0; n < 256; n++) { 212 rs.i = (rs.i + 1); 213 si = rs.s[rs.i]; 214 rs.j = (rs.j + si + dat[n % datlen]); 215 rs.s[rs.i] = rs.s[rs.j]; 216 rs.s[rs.j] = si; 217 } 218 rs.j = rs.i; 219 } 220 221 static void 222 arc4_stir(void) 223 { 224 int done, fd, i; 225 struct { 226 struct timeval tv; 227 pid_t pid; 228 uint8_t rnd[KEYSIZE]; 229 } rdat; 230 231 if (!rs_initialized) { 232 arc4_init(); 233 rs_initialized = 1; 234 } 235 done = 0; 236 fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0); 237 if (fd >= 0) { 238 if (read(fd, &rdat, KEYSIZE) == KEYSIZE) 239 done = 1; 240 (void)close(fd); 241 } 242 if (!done) { 243 (void)gettimeofday(&rdat.tv, NULL); 244 rdat.pid = getpid(); 245 /* We'll just take whatever was on the stack too... */ 246 } 247 248 arc4_addrandom((uint8_t *)&rdat, KEYSIZE); 249 250 /* 251 * Discard early keystream, as per recommendations in: 252 * "(Not So) Random Shuffles of RC4" by Ilya Mironov. 253 * As per the Network Operations Division, cryptographic requirements 254 * published on wikileaks on March 2017. 255 */ 256 257 for (i = 0; i < 3072; i++) 258 (void)arc4_getbyte(); 259 arc4_count = 1600000; 260 } 261 262 static void 263 arc4_stir_if_needed(void) 264 { 265 pid_t pid = getpid(); 266 267 if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) { 268 arc4_stir_pid = pid; 269 arc4_stir(); 270 } 271 } 272 273 static inline uint8_t 274 arc4_getbyte(void) 275 { 276 uint8_t si, sj; 277 278 rs.i = (rs.i + 1); 279 si = rs.s[rs.i]; 280 rs.j = (rs.j + si); 281 sj = rs.s[rs.j]; 282 rs.s[rs.i] = sj; 283 rs.s[rs.j] = si; 284 return (rs.s[(si + sj) & 0xff]); 285 } 286 287 static void 288 la_arc4random_buf(void *_buf, size_t n) 289 { 290 uint8_t *buf = (uint8_t *)_buf; 291 _ARC4_LOCK(); 292 arc4_stir_if_needed(); 293 while (n--) { 294 if (--arc4_count <= 0) 295 arc4_stir(); 296 buf[n] = arc4_getbyte(); 297 } 298 _ARC4_UNLOCK(); 299 } 300 301 #endif /* !HAVE_ARC4RANDOM_BUF */ 302