Ticket #13869: 0005-libs-bsd-add-arc4random-3.patch

File 0005-libs-bsd-add-arc4random-3.patch, 16.1 KB (added by leorize, 6 years ago)
  • headers/compatibility/bsd/stdlib.h

    From 477767615f768b41a7d4062d2841114fba73166d Mon Sep 17 00:00:00 2001
    From: Leorize <alaviss@users.noreply.github.com>
    Date: Thu, 14 Dec 2017 08:15:01 +0700
    Subject: [PATCH 5/5] libs/bsd: add arc4random(3)
    
    ---
     headers/compatibility/bsd/stdlib.h      |   4 +
     headers/private/libbsd/chacha_private.h | 222 ++++++++++++++++++++++++++
     src/libs/bsd/Jamfile                    |   3 +
     src/libs/bsd/arc4random.c               | 265 ++++++++++++++++++++++++++++++++
     src/libs/bsd/arc4random_uniform.c       |  56 +++++++
     5 files changed, 550 insertions(+)
     create mode 100644 headers/private/libbsd/chacha_private.h
     create mode 100644 src/libs/bsd/arc4random.c
     create mode 100644 src/libs/bsd/arc4random_uniform.c
    
    diff --git a/headers/compatibility/bsd/stdlib.h b/headers/compatibility/bsd/stdlib.h
    index d65871f8..ae800480 100644
    a b  
    1111
    1212#ifdef _BSD_SOURCE
    1313
     14#include <stdint.h>
    1415
    1516#ifdef __cplusplus
    1617extern "C" {
    extern "C" {  
    1920int         daemon(int noChangeDir, int noClose);
    2021const char  *getprogname(void);
    2122void        setprogname(const char *programName);
     23uint32_t arc4random(void);
     24void arc4random_buf(void *buf, size_t nbytes);
     25uint32_t arc4random_uniform(uint32_t upper_bound);
    2226
    2327#ifdef __cplusplus
    2428}
  • new file headers/private/libbsd/chacha_private.h

    diff --git a/headers/private/libbsd/chacha_private.h b/headers/private/libbsd/chacha_private.h
    new file mode 100644
    index 00000000..5aae8d86
    - +  
     1/*
     2chacha-merged.c version 20080118
     3D. J. Bernstein
     4Public domain.
     5*/
     6
     7/* $OpenBSD$ */
     8
     9typedef unsigned char u8;
     10typedef unsigned int u32;
     11
     12typedef struct
     13{
     14  u32 input[16]; /* could be compressed */
     15} chacha_ctx;
     16
     17#define U8C(v) (v##U)
     18#define U32C(v) (v##U)
     19
     20#define U8V(v) ((u8)(v) & U8C(0xFF))
     21#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
     22
     23#define ROTL32(v, n) \
     24  (U32V((v) << (n)) | ((v) >> (32 - (n))))
     25
     26#define U8TO32_LITTLE(p) \
     27  (((u32)((p)[0])      ) | \
     28   ((u32)((p)[1]) <<  8) | \
     29   ((u32)((p)[2]) << 16) | \
     30   ((u32)((p)[3]) << 24))
     31
     32#define U32TO8_LITTLE(p, v) \
     33  do { \
     34    (p)[0] = U8V((v)      ); \
     35    (p)[1] = U8V((v) >>  8); \
     36    (p)[2] = U8V((v) >> 16); \
     37    (p)[3] = U8V((v) >> 24); \
     38  } while (0)
     39
     40#define ROTATE(v,c) (ROTL32(v,c))
     41#define XOR(v,w) ((v) ^ (w))
     42#define PLUS(v,w) (U32V((v) + (w)))
     43#define PLUSONE(v) (PLUS((v),1))
     44
     45#define QUARTERROUND(a,b,c,d) \
     46  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
     47  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
     48  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
     49  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
     50
     51static const char sigma[16] = "expand 32-byte k";
     52static const char tau[16] = "expand 16-byte k";
     53
     54static void
     55chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
     56{
     57  const char *constants;
     58
     59  x->input[4] = U8TO32_LITTLE(k + 0);
     60  x->input[5] = U8TO32_LITTLE(k + 4);
     61  x->input[6] = U8TO32_LITTLE(k + 8);
     62  x->input[7] = U8TO32_LITTLE(k + 12);
     63  if (kbits == 256) { /* recommended */
     64    k += 16;
     65    constants = sigma;
     66  } else { /* kbits == 128 */
     67    constants = tau;
     68  }
     69  x->input[8] = U8TO32_LITTLE(k + 0);
     70  x->input[9] = U8TO32_LITTLE(k + 4);
     71  x->input[10] = U8TO32_LITTLE(k + 8);
     72  x->input[11] = U8TO32_LITTLE(k + 12);
     73  x->input[0] = U8TO32_LITTLE(constants + 0);
     74  x->input[1] = U8TO32_LITTLE(constants + 4);
     75  x->input[2] = U8TO32_LITTLE(constants + 8);
     76  x->input[3] = U8TO32_LITTLE(constants + 12);
     77}
     78
     79static void
     80chacha_ivsetup(chacha_ctx *x,const u8 *iv)
     81{
     82  x->input[12] = 0;
     83  x->input[13] = 0;
     84  x->input[14] = U8TO32_LITTLE(iv + 0);
     85  x->input[15] = U8TO32_LITTLE(iv + 4);
     86}
     87
     88static void
     89chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
     90{
     91  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
     92  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
     93  u8 *ctarget = NULL;
     94  u8 tmp[64];
     95  unsigned int i;
     96
     97  if (!bytes) return;
     98
     99  j0 = x->input[0];
     100  j1 = x->input[1];
     101  j2 = x->input[2];
     102  j3 = x->input[3];
     103  j4 = x->input[4];
     104  j5 = x->input[5];
     105  j6 = x->input[6];
     106  j7 = x->input[7];
     107  j8 = x->input[8];
     108  j9 = x->input[9];
     109  j10 = x->input[10];
     110  j11 = x->input[11];
     111  j12 = x->input[12];
     112  j13 = x->input[13];
     113  j14 = x->input[14];
     114  j15 = x->input[15];
     115
     116  for (;;) {
     117    if (bytes < 64) {
     118      for (i = 0;i < bytes;++i) tmp[i] = m[i];
     119      m = tmp;
     120      ctarget = c;
     121      c = tmp;
     122    }
     123    x0 = j0;
     124    x1 = j1;
     125    x2 = j2;
     126    x3 = j3;
     127    x4 = j4;
     128    x5 = j5;
     129    x6 = j6;
     130    x7 = j7;
     131    x8 = j8;
     132    x9 = j9;
     133    x10 = j10;
     134    x11 = j11;
     135    x12 = j12;
     136    x13 = j13;
     137    x14 = j14;
     138    x15 = j15;
     139    for (i = 20;i > 0;i -= 2) {
     140      QUARTERROUND( x0, x4, x8,x12)
     141      QUARTERROUND( x1, x5, x9,x13)
     142      QUARTERROUND( x2, x6,x10,x14)
     143      QUARTERROUND( x3, x7,x11,x15)
     144      QUARTERROUND( x0, x5,x10,x15)
     145      QUARTERROUND( x1, x6,x11,x12)
     146      QUARTERROUND( x2, x7, x8,x13)
     147      QUARTERROUND( x3, x4, x9,x14)
     148    }
     149    x0 = PLUS(x0,j0);
     150    x1 = PLUS(x1,j1);
     151    x2 = PLUS(x2,j2);
     152    x3 = PLUS(x3,j3);
     153    x4 = PLUS(x4,j4);
     154    x5 = PLUS(x5,j5);
     155    x6 = PLUS(x6,j6);
     156    x7 = PLUS(x7,j7);
     157    x8 = PLUS(x8,j8);
     158    x9 = PLUS(x9,j9);
     159    x10 = PLUS(x10,j10);
     160    x11 = PLUS(x11,j11);
     161    x12 = PLUS(x12,j12);
     162    x13 = PLUS(x13,j13);
     163    x14 = PLUS(x14,j14);
     164    x15 = PLUS(x15,j15);
     165
     166#ifndef KEYSTREAM_ONLY
     167    x0 = XOR(x0,U8TO32_LITTLE(m + 0));
     168    x1 = XOR(x1,U8TO32_LITTLE(m + 4));
     169    x2 = XOR(x2,U8TO32_LITTLE(m + 8));
     170    x3 = XOR(x3,U8TO32_LITTLE(m + 12));
     171    x4 = XOR(x4,U8TO32_LITTLE(m + 16));
     172    x5 = XOR(x5,U8TO32_LITTLE(m + 20));
     173    x6 = XOR(x6,U8TO32_LITTLE(m + 24));
     174    x7 = XOR(x7,U8TO32_LITTLE(m + 28));
     175    x8 = XOR(x8,U8TO32_LITTLE(m + 32));
     176    x9 = XOR(x9,U8TO32_LITTLE(m + 36));
     177    x10 = XOR(x10,U8TO32_LITTLE(m + 40));
     178    x11 = XOR(x11,U8TO32_LITTLE(m + 44));
     179    x12 = XOR(x12,U8TO32_LITTLE(m + 48));
     180    x13 = XOR(x13,U8TO32_LITTLE(m + 52));
     181    x14 = XOR(x14,U8TO32_LITTLE(m + 56));
     182    x15 = XOR(x15,U8TO32_LITTLE(m + 60));
     183#endif
     184
     185    j12 = PLUSONE(j12);
     186    if (!j12) {
     187      j13 = PLUSONE(j13);
     188      /* stopping at 2^70 bytes per nonce is user's responsibility */
     189    }
     190
     191    U32TO8_LITTLE(c + 0,x0);
     192    U32TO8_LITTLE(c + 4,x1);
     193    U32TO8_LITTLE(c + 8,x2);
     194    U32TO8_LITTLE(c + 12,x3);
     195    U32TO8_LITTLE(c + 16,x4);
     196    U32TO8_LITTLE(c + 20,x5);
     197    U32TO8_LITTLE(c + 24,x6);
     198    U32TO8_LITTLE(c + 28,x7);
     199    U32TO8_LITTLE(c + 32,x8);
     200    U32TO8_LITTLE(c + 36,x9);
     201    U32TO8_LITTLE(c + 40,x10);
     202    U32TO8_LITTLE(c + 44,x11);
     203    U32TO8_LITTLE(c + 48,x12);
     204    U32TO8_LITTLE(c + 52,x13);
     205    U32TO8_LITTLE(c + 56,x14);
     206    U32TO8_LITTLE(c + 60,x15);
     207
     208    if (bytes <= 64) {
     209      if (bytes < 64) {
     210        for (i = 0;i < bytes;++i) ctarget[i] = c[i];
     211      }
     212      x->input[12] = j12;
     213      x->input[13] = j13;
     214      return;
     215    }
     216    bytes -= 64;
     217    c += 64;
     218#ifndef KEYSTREAM_ONLY
     219    m += 64;
     220#endif
     221  }
     222}
  • src/libs/bsd/Jamfile

    diff --git a/src/libs/bsd/Jamfile b/src/libs/bsd/Jamfile
    index e14b3766..1606ebe6 100644
    a b SubDir HAIKU_TOP src libs bsd ;  
    33SetSubDirSupportedPlatforms $(HAIKU_BONE_COMPATIBLE_PLATFORMS) ;
    44
    55UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
     6UsePrivateHeaders libbsd ;
    67
    78SubDirCcFlags [ FDefines _BSD_SOURCE=1 ] ;
    89SubDirC++Flags [ FDefines _BSD_SOURCE=1 ] ;
    local architectureObject ;  
    1112for architectureObject in [ MultiArchSubDirSetup ] {
    1213    on $(architectureObject) {
    1314        SharedLibrary [ MultiArchDefaultGristFiles libbsd.so ] :
     15            arc4random.c
     16            arc4random_uniform.c
    1417            daemon.c
    1518            err.c
    1619            explicit_bzero.c
  • new file src/libs/bsd/arc4random.c

    diff --git a/src/libs/bsd/arc4random.c b/src/libs/bsd/arc4random.c
    new file mode 100644
    index 00000000..9a0ac4d4
    - +  
     1/*  $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $    */
     2
     3/*
     4 * Copyright (c) 1996, David Mazieres <dm@uun.org>
     5 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
     6 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
     7 * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
     8 *
     9 * Permission to use, copy, modify, and distribute this software for any
     10 * purpose with or without fee is hereby granted, provided that the above
     11 * copyright notice and this permission notice appear in all copies.
     12 *
     13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     20 */
     21
     22/*
     23 * ChaCha based random number generator for OpenBSD.
     24 */
     25
     26#include <fcntl.h>
     27#include <limits.h>
     28#include <signal.h>
     29#include <stdint.h>
     30#include <stdlib.h>
     31#include <string.h>
     32#include <unistd.h>
     33#include <sys/types.h>
     34#include <sys/time.h>
     35
     36#define KEYSTREAM_ONLY
     37#include <chacha_private.h>
     38
     39#define minimum(a, b) ((a) < (b) ? (a) : (b))
     40
     41#if defined(__GNUC__) || defined(_MSC_VER)
     42#define inline __inline
     43#else               /* __GNUC__ || _MSC_VER */
     44#define inline
     45#endif              /* !__GNUC__ && !_MSC_VER */
     46
     47#define KEYSZ   32
     48#define IVSZ    8
     49#define BLOCKSZ 64
     50#define RSBUFSZ (16*BLOCKSZ)
     51
     52/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
     53static struct _rs {
     54    size_t      rs_have;    /* valid bytes at end of rs_buf */
     55    size_t      rs_count;   /* bytes till reseed */
     56} *rs;
     57
     58/* Maybe be preserved in fork children, if _rs_allocate() decides. */
     59static struct _rsx {
     60    chacha_ctx  rs_chacha;  /* chacha context for random keystream */
     61    u_char      rs_buf[RSBUFSZ];    /* keystream blocks */
     62} *rsx;
     63
     64
     65/*
     66 * Stub functions for portability.
     67 */
     68
     69#include <sys/mman.h>
     70
     71#include <pthread.h>
     72#include <signal.h>
     73
     74static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
     75#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx)
     76#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx)
     77
     78#ifdef __GLIBC__
     79extern void *__dso_handle;
     80extern int __register_atfork(void (*)(void), void(*)(void), void (*)(void), void *);
     81#define _ARC4_ATFORK(f) __register_atfork(NULL, NULL, (f), __dso_handle)
     82#else
     83/*
     84 * Unfortunately, pthread_atfork() is broken on FreeBSD (at least 9 and 10) if
     85 * a program does not link to -lthr. Callbacks registered with pthread_atfork()
     86 * appear to fail silently. So, it is not always possible to detect a PID
     87 * wraparound.
     88 */
     89#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f))
     90#endif
     91
     92static inline void
     93_getentropy_fail(void)
     94{
     95    raise(SIGKILL);
     96}
     97
     98static volatile sig_atomic_t _rs_forked;
     99
     100static inline void
     101_rs_forkhandler(void)
     102{
     103    _rs_forked = 1;
     104}
     105
     106static inline void
     107_rs_forkdetect(void)
     108{
     109    static pid_t _rs_pid = 0;
     110    pid_t pid = getpid();
     111
     112    if (_rs_pid == 0 || _rs_pid != pid || _rs_forked) {
     113        _rs_pid = pid;
     114        _rs_forked = 0;
     115        if (rs)
     116            memset(rs, 0, sizeof(*rs));
     117    }
     118}
     119
     120static inline int
     121_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
     122{
     123    if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
     124        MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
     125        return (-1);
     126
     127    if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
     128        MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
     129        munmap(*rsp, sizeof(**rsp));
     130        return (-1);
     131    }
     132
     133    _ARC4_ATFORK(_rs_forkhandler);
     134    return (0);
     135}
     136
     137static inline void _rs_rekey(u_char *dat, size_t datlen);
     138
     139static inline void
     140_rs_init(u_char *buf, size_t n)
     141{
     142    if (n < KEYSZ + IVSZ)
     143        return;
     144
     145    if (rs == NULL) {
     146        if (_rs_allocate(&rs, &rsx) == -1)
     147            abort();
     148    }
     149
     150    chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0);
     151    chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
     152}
     153
     154static void
     155_rs_stir(void)
     156{
     157    u_char rnd[KEYSZ + IVSZ];
     158
     159    if (getentropy(rnd, sizeof rnd) == -1)
     160        _getentropy_fail();
     161
     162    if (!rs)
     163        _rs_init(rnd, sizeof(rnd));
     164    else
     165        _rs_rekey(rnd, sizeof(rnd));
     166    explicit_bzero(rnd, sizeof(rnd));   /* discard source seed */
     167
     168    /* invalidate rs_buf */
     169    rs->rs_have = 0;
     170    memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
     171
     172    rs->rs_count = 1600000;
     173}
     174
     175static inline void
     176_rs_stir_if_needed(size_t len)
     177{
     178    _rs_forkdetect();
     179    if (!rs || rs->rs_count <= len)
     180        _rs_stir();
     181    if (rs->rs_count <= len)
     182        rs->rs_count = 0;
     183    else
     184        rs->rs_count -= len;
     185}
     186
     187static inline void
     188_rs_rekey(u_char *dat, size_t datlen)
     189{
     190#ifndef KEYSTREAM_ONLY
     191    memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
     192#endif
     193    /* fill rs_buf with the keystream */
     194    chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
     195        rsx->rs_buf, sizeof(rsx->rs_buf));
     196    /* mix in optional user provided data */
     197    if (dat) {
     198        size_t i, m;
     199
     200        m = minimum(datlen, KEYSZ + IVSZ);
     201        for (i = 0; i < m; i++)
     202            rsx->rs_buf[i] ^= dat[i];
     203    }
     204    /* immediately reinit for backtracking resistance */
     205    _rs_init(rsx->rs_buf, KEYSZ + IVSZ);
     206    memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
     207    rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
     208}
     209
     210static inline void
     211_rs_random_buf(void *_buf, size_t n)
     212{
     213    u_char *buf = (u_char *)_buf;
     214    u_char *keystream;
     215    size_t m;
     216
     217    _rs_stir_if_needed(n);
     218    while (n > 0) {
     219        if (rs->rs_have > 0) {
     220            m = minimum(n, rs->rs_have);
     221            keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
     222                - rs->rs_have;
     223            memcpy(buf, keystream, m);
     224            memset(keystream, 0, m);
     225            buf += m;
     226            n -= m;
     227            rs->rs_have -= m;
     228        }
     229        if (rs->rs_have == 0)
     230            _rs_rekey(NULL, 0);
     231    }
     232}
     233
     234static inline void
     235_rs_random_u32(uint32_t *val)
     236{
     237    u_char *keystream;
     238
     239    _rs_stir_if_needed(sizeof(*val));
     240    if (rs->rs_have < sizeof(*val))
     241        _rs_rekey(NULL, 0);
     242    keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
     243    memcpy(val, keystream, sizeof(*val));
     244    memset(keystream, 0, sizeof(*val));
     245    rs->rs_have -= sizeof(*val);
     246}
     247
     248uint32_t
     249arc4random(void)
     250{
     251    uint32_t val;
     252
     253    _ARC4_LOCK();
     254    _rs_random_u32(&val);
     255    _ARC4_UNLOCK();
     256    return val;
     257}
     258
     259void
     260arc4random_buf(void *buf, size_t n)
     261{
     262    _ARC4_LOCK();
     263    _rs_random_buf(buf, n);
     264    _ARC4_UNLOCK();
     265}
  • new file src/libs/bsd/arc4random_uniform.c

    diff --git a/src/libs/bsd/arc4random_uniform.c b/src/libs/bsd/arc4random_uniform.c
    new file mode 100644
    index 00000000..2d224345
    - +  
     1/*  $OpenBSD: arc4random_uniform.c,v 1.2 2015/09/13 08:31:47 guenther Exp $ */
     2
     3/*
     4 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
     5 *
     6 * Permission to use, copy, modify, and distribute this software for any
     7 * purpose with or without fee is hereby granted, provided that the above
     8 * copyright notice and this permission notice appear in all copies.
     9 *
     10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17 */
     18
     19#include <sys/types.h>
     20#include <stdlib.h>
     21
     22/*
     23 * Calculate a uniformly distributed random number less than upper_bound
     24 * avoiding "modulo bias".
     25 *
     26 * Uniformity is achieved by generating new random numbers until the one
     27 * returned is outside the range [0, 2**32 % upper_bound).  This
     28 * guarantees the selected random number will be inside
     29 * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
     30 * after reduction modulo upper_bound.
     31 */
     32uint32_t
     33arc4random_uniform(uint32_t upper_bound)
     34{
     35    uint32_t r, min;
     36
     37    if (upper_bound < 2)
     38        return 0;
     39
     40    /* 2**32 % x == (2**32 - x) % x */
     41    min = -upper_bound % upper_bound;
     42
     43    /*
     44     * This could theoretically loop forever but each retry has
     45     * p > 0.5 (worst case, usually far better) of selecting a
     46     * number inside the range we need, so it should rarely need
     47     * to re-roll.
     48     */
     49    for (;;) {
     50        r = arc4random();
     51        if (r >= min)
     52            break;
     53    }
     54
     55    return r % upper_bound;
     56}