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