This source file includes following definitions.
- arc4_init
- arc4_addrandom
- read_all
- arc4_seed_win32
- arc4_seed_sysctl_linux
- arc4_seed_sysctl_bsd
- arc4_seed_proc_sys_kernel_random_uuid
- arc4_seed_urandom_helper_
- arc4_seed_urandom
- arc4_seed
- arc4_stir
- arc4_stir_if_needed
- arc4_getbyte
- arc4_getword
- arc4random_stir
- arc4random_addrandom
- arc4random
- arc4random_buf
- arc4random_uniform
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 
  43 
  44 #ifndef ARC4RANDOM_EXPORT
  45 #define ARC4RANDOM_EXPORT
  46 #endif
  47 
  48 #ifndef ARC4RANDOM_UINT32
  49 #define ARC4RANDOM_UINT32 uint32_t
  50 #endif
  51 
  52 #ifndef ARC4RANDOM_NO_INCLUDES
  53 #ifdef WIN32
  54 #include <wincrypt.h>
  55 #include <process.h>
  56 #else
  57 #include <fcntl.h>
  58 #include <unistd.h>
  59 #include <sys/param.h>
  60 #include <sys/time.h>
  61 #ifdef _EVENT_HAVE_SYS_SYSCTL_H
  62 #include <sys/sysctl.h>
  63 #endif
  64 #endif
  65 #include <limits.h>
  66 #include <stdlib.h>
  67 #include <string.h>
  68 #endif
  69 
  70 
  71 #define ADD_ENTROPY 32
  72 
  73 
  74 #define BYTES_BEFORE_RESEED 1600000
  75 
  76 struct arc4_stream {
  77         unsigned char i;
  78         unsigned char j;
  79         unsigned char s[256];
  80 };
  81 
  82 #ifdef WIN32
  83 #define getpid _getpid
  84 #define pid_t int
  85 #endif
  86 
  87 static int rs_initialized;
  88 static struct arc4_stream rs;
  89 static pid_t arc4_stir_pid;
  90 static int arc4_count;
  91 static int arc4_seeded_ok;
  92 
  93 static inline unsigned char arc4_getbyte(void);
  94 
  95 static inline void
  96 arc4_init(void)
  97 {
  98         int     n;
  99 
 100         for (n = 0; n < 256; n++)
 101                 rs.s[n] = n;
 102         rs.i = 0;
 103         rs.j = 0;
 104 }
 105 
 106 static inline void
 107 arc4_addrandom(const unsigned char *dat, int datlen)
 108 {
 109         int     n;
 110         unsigned char si;
 111 
 112         rs.i--;
 113         for (n = 0; n < 256; n++) {
 114                 rs.i = (rs.i + 1);
 115                 si = rs.s[rs.i];
 116                 rs.j = (rs.j + si + dat[n % datlen]);
 117                 rs.s[rs.i] = rs.s[rs.j];
 118                 rs.s[rs.j] = si;
 119         }
 120         rs.j = rs.i;
 121 }
 122 
 123 #ifndef WIN32
 124 static ssize_t
 125 read_all(int fd, unsigned char *buf, size_t count)
 126 {
 127         size_t numread = 0;
 128         ssize_t result;
 129 
 130         while (numread < count) {
 131                 result = read(fd, buf+numread, count-numread);
 132                 if (result<0)
 133                         return -1;
 134                 else if (result == 0)
 135                         break;
 136                 numread += result;
 137         }
 138 
 139         return (ssize_t)numread;
 140 }
 141 #endif
 142 
 143 #ifdef WIN32
 144 #define TRY_SEED_WIN32
 145 static int
 146 arc4_seed_win32(void)
 147 {
 148         
 149         static int provider_set = 0;
 150         static HCRYPTPROV provider;
 151         unsigned char buf[ADD_ENTROPY];
 152 
 153         if (!provider_set) {
 154                 if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
 155                     CRYPT_VERIFYCONTEXT)) {
 156                         if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
 157                                 return -1;
 158                 }
 159                 provider_set = 1;
 160         }
 161         if (!CryptGenRandom(provider, sizeof(buf), buf))
 162                 return -1;
 163         arc4_addrandom(buf, sizeof(buf));
 164         evutil_memclear_(buf, sizeof(buf));
 165         arc4_seeded_ok = 1;
 166         return 0;
 167 }
 168 #endif
 169 
 170 #if defined(_EVENT_HAVE_SYS_SYSCTL_H) && defined(_EVENT_HAVE_SYSCTL)
 171 #if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_RANDOM && _EVENT_HAVE_DECL_RANDOM_UUID
 172 #define TRY_SEED_SYSCTL_LINUX
 173 static int
 174 arc4_seed_sysctl_linux(void)
 175 {
 176         
 177 
 178 
 179 
 180         int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
 181         unsigned char buf[ADD_ENTROPY];
 182         size_t len, n;
 183         unsigned i;
 184         int any_set;
 185 
 186         memset(buf, 0, sizeof(buf));
 187 
 188         for (len = 0; len < sizeof(buf); len += n) {
 189                 n = sizeof(buf) - len;
 190 
 191                 if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0))
 192                         return -1;
 193         }
 194         
 195         for (i=0,any_set=0; i<sizeof(buf); ++i) {
 196                 any_set |= buf[i];
 197         }
 198         if (!any_set)
 199                 return -1;
 200 
 201         arc4_addrandom(buf, sizeof(buf));
 202         evutil_memclear_(buf, sizeof(buf));
 203         arc4_seeded_ok = 1;
 204         return 0;
 205 }
 206 #endif
 207 
 208 #if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_ARND
 209 #define TRY_SEED_SYSCTL_BSD
 210 static int
 211 arc4_seed_sysctl_bsd(void)
 212 {
 213         
 214 
 215 
 216 
 217         int mib[] = { CTL_KERN, KERN_ARND };
 218         unsigned char buf[ADD_ENTROPY];
 219         size_t len, n;
 220         int i, any_set;
 221 
 222         memset(buf, 0, sizeof(buf));
 223 
 224         len = sizeof(buf);
 225         if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
 226                 for (len = 0; len < sizeof(buf); len += sizeof(unsigned)) {
 227                         n = sizeof(unsigned);
 228                         if (n + len > sizeof(buf))
 229                             n = len - sizeof(buf);
 230                         if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1)
 231                                 return -1;
 232                 }
 233         }
 234         
 235         for (i=any_set=0; i<sizeof(buf); ++i) {
 236                 any_set |= buf[i];
 237         }
 238         if (!any_set)
 239                 return -1;
 240 
 241         arc4_addrandom(buf, sizeof(buf));
 242         evutil_memclear_(buf, sizeof(buf));
 243         arc4_seeded_ok = 1;
 244         return 0;
 245 }
 246 #endif
 247 #endif 
 248 
 249 #ifdef __linux__
 250 #define TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
 251 static int
 252 arc4_seed_proc_sys_kernel_random_uuid(void)
 253 {
 254         
 255 
 256 
 257 
 258         int fd;
 259         char buf[128];
 260         unsigned char entropy[64];
 261         int bytes, n, i, nybbles;
 262         for (bytes = 0; bytes<ADD_ENTROPY; ) {
 263                 fd = evutil_open_closeonexec("/proc/sys/kernel/random/uuid", O_RDONLY, 0);
 264                 if (fd < 0)
 265                         return -1;
 266                 n = read(fd, buf, sizeof(buf));
 267                 close(fd);
 268                 if (n<=0)
 269                         return -1;
 270                 memset(entropy, 0, sizeof(entropy));
 271                 for (i=nybbles=0; i<n; ++i) {
 272                         if (EVUTIL_ISXDIGIT(buf[i])) {
 273                                 int nyb = evutil_hex_char_to_int(buf[i]);
 274                                 if (nybbles & 1) {
 275                                         entropy[nybbles/2] |= nyb;
 276                                 } else {
 277                                         entropy[nybbles/2] |= nyb<<4;
 278                                 }
 279                                 ++nybbles;
 280                         }
 281                 }
 282                 if (nybbles < 2)
 283                         return -1;
 284                 arc4_addrandom(entropy, nybbles/2);
 285                 bytes += nybbles/2;
 286         }
 287         evutil_memclear_(entropy, sizeof(entropy));
 288         evutil_memclear_(buf, sizeof(buf));
 289         arc4_seeded_ok = 1;
 290         return 0;
 291 }
 292 #endif
 293 
 294 #ifndef WIN32
 295 #define TRY_SEED_URANDOM
 296 static char *arc4random_urandom_filename = NULL;
 297 
 298 static int arc4_seed_urandom_helper_(const char *fname)
 299 {
 300         unsigned char buf[ADD_ENTROPY];
 301         int fd;
 302         size_t n;
 303 
 304         fd = evutil_open_closeonexec(fname, O_RDONLY, 0);
 305         if (fd<0)
 306                 return -1;
 307         n = read_all(fd, buf, sizeof(buf));
 308         close(fd);
 309         if (n != sizeof(buf))
 310                 return -1;
 311         arc4_addrandom(buf, sizeof(buf));
 312         evutil_memclear_(buf, sizeof(buf));
 313         arc4_seeded_ok = 1;
 314         return 0;
 315 }
 316 
 317 static int
 318 arc4_seed_urandom(void)
 319 {
 320         
 321         static const char *filenames[] = {
 322                 "/dev/srandom", "/dev/urandom", "/dev/random", NULL
 323         };
 324         int i;
 325         if (arc4random_urandom_filename)
 326                 return arc4_seed_urandom_helper_(arc4random_urandom_filename);
 327 
 328         for (i = 0; filenames[i]; ++i) {
 329                 if (arc4_seed_urandom_helper_(filenames[i]) == 0) {
 330                         return 0;
 331                 }
 332         }
 333 
 334         return -1;
 335 }
 336 #endif
 337 
 338 static int
 339 arc4_seed(void)
 340 {
 341         int ok = 0;
 342         
 343 
 344 
 345 #ifdef TRY_SEED_WIN32
 346         if (0 == arc4_seed_win32())
 347                 ok = 1;
 348 #endif
 349 #ifdef TRY_SEED_URANDOM
 350         if (0 == arc4_seed_urandom())
 351                 ok = 1;
 352 #endif
 353 #ifdef TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
 354         if (arc4random_urandom_filename == NULL &&
 355             0 == arc4_seed_proc_sys_kernel_random_uuid())
 356                 ok = 1;
 357 #endif
 358 #ifdef TRY_SEED_SYSCTL_LINUX
 359         
 360 
 361         if (!ok && 0 == arc4_seed_sysctl_linux())
 362                 ok = 1;
 363 #endif
 364 #ifdef TRY_SEED_SYSCTL_BSD
 365         if (0 == arc4_seed_sysctl_bsd())
 366                 ok = 1;
 367 #endif
 368         return ok ? 0 : -1;
 369 }
 370 
 371 static int
 372 arc4_stir(void)
 373 {
 374         int     i;
 375 
 376         if (!rs_initialized) {
 377                 arc4_init();
 378                 rs_initialized = 1;
 379         }
 380 
 381         arc4_seed();
 382         if (!arc4_seeded_ok)
 383                 return -1;
 384 
 385         
 386 
 387 
 388 
 389 
 390 
 391 
 392 
 393 
 394 
 395 
 396 
 397 
 398 
 399 
 400 
 401 
 402 
 403         for (i = 0; i < 12*256; i++)
 404                 (void)arc4_getbyte();
 405 
 406         arc4_count = BYTES_BEFORE_RESEED;
 407 
 408         return 0;
 409 }
 410 
 411 
 412 static void
 413 arc4_stir_if_needed(void)
 414 {
 415         pid_t pid = getpid();
 416 
 417         if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid)
 418         {
 419                 arc4_stir_pid = pid;
 420                 arc4_stir();
 421         }
 422 }
 423 
 424 static inline unsigned char
 425 arc4_getbyte(void)
 426 {
 427         unsigned char si, sj;
 428 
 429         rs.i = (rs.i + 1);
 430         si = rs.s[rs.i];
 431         rs.j = (rs.j + si);
 432         sj = rs.s[rs.j];
 433         rs.s[rs.i] = sj;
 434         rs.s[rs.j] = si;
 435         return (rs.s[(si + sj) & 0xff]);
 436 }
 437 
 438 static inline unsigned int
 439 arc4_getword(void)
 440 {
 441         unsigned int val;
 442 
 443         val = arc4_getbyte() << 24;
 444         val |= arc4_getbyte() << 16;
 445         val |= arc4_getbyte() << 8;
 446         val |= arc4_getbyte();
 447 
 448         return val;
 449 }
 450 
 451 #ifndef ARC4RANDOM_NOSTIR
 452 ARC4RANDOM_EXPORT int
 453 arc4random_stir(void)
 454 {
 455         int val;
 456         _ARC4_LOCK();
 457         val = arc4_stir();
 458         _ARC4_UNLOCK();
 459         return val;
 460 }
 461 #endif
 462 
 463 
 464 
 465 
 466 
 467 #if 0
 468 #ifndef ARC4RANDOM_NOADDRANDOM
 469 ARC4RANDOM_EXPORT void
 470 arc4random_addrandom(const unsigned char *dat, int datlen)
 471 {
 472         int j;
 473         _ARC4_LOCK();
 474         if (!rs_initialized)
 475                 arc4_stir();
 476         for (j = 0; j < datlen; j += 256) {
 477                 
 478 
 479 
 480 
 481                 arc4_addrandom(dat + j, datlen - j);
 482         }
 483         _ARC4_UNLOCK();
 484 }
 485 #endif
 486 #endif
 487 
 488 #ifndef ARC4RANDOM_NORANDOM
 489 ARC4RANDOM_EXPORT ARC4RANDOM_UINT32
 490 arc4random(void)
 491 {
 492         ARC4RANDOM_UINT32 val;
 493         _ARC4_LOCK();
 494         arc4_count -= 4;
 495         arc4_stir_if_needed();
 496         val = arc4_getword();
 497         _ARC4_UNLOCK();
 498         return val;
 499 }
 500 #endif
 501 
 502 ARC4RANDOM_EXPORT void
 503 arc4random_buf(void *_buf, size_t n)
 504 {
 505         unsigned char *buf = _buf;
 506         _ARC4_LOCK();
 507         arc4_stir_if_needed();
 508         while (n--) {
 509                 if (--arc4_count <= 0)
 510                         arc4_stir();
 511                 buf[n] = arc4_getbyte();
 512         }
 513         _ARC4_UNLOCK();
 514 }
 515 
 516 #ifndef ARC4RANDOM_NOUNIFORM
 517 
 518 
 519 
 520 
 521 
 522 
 523 
 524 
 525 
 526 
 527 ARC4RANDOM_EXPORT unsigned int
 528 arc4random_uniform(unsigned int upper_bound)
 529 {
 530         ARC4RANDOM_UINT32 r, min;
 531 
 532         if (upper_bound < 2)
 533                 return 0;
 534 
 535 #if (UINT_MAX > 0xffffffffUL)
 536         min = 0x100000000UL % upper_bound;
 537 #else
 538         
 539         if (upper_bound > 0x80000000)
 540                 min = 1 + ~upper_bound;         
 541         else {
 542                 
 543                 min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
 544         }
 545 #endif
 546 
 547         
 548 
 549 
 550 
 551 
 552 
 553         for (;;) {
 554                 r = arc4random();
 555                 if (r >= min)
 556                         break;
 557         }
 558 
 559         return r % upper_bound;
 560 }
 561 #endif