summaryrefslogtreecommitdiff
path: root/openbsd-compat/bsd-arc4random.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2008-05-19 14:47:37 +1000
committerDamien Miller <djm@mindrot.org>2008-05-19 14:47:37 +1000
commita4be7c23fdcf8a1da5420068dc4bd4db45af9c9c (patch)
tree30791da826e91a68016c4a969d8d924fb9778312 /openbsd-compat/bsd-arc4random.c
parent25434de4606924a31016e42728c4acdf6de90cc7 (diff)
- (djm) [openbsd-compat/bsd-arc4random.c openbsd-compat/openbsd-compat.c]
[configure.ac] Implement arc4random_buf(), import implementation of arc4random_uniform() from OpenBSD
Diffstat (limited to 'openbsd-compat/bsd-arc4random.c')
-rw-r--r--openbsd-compat/bsd-arc4random.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/openbsd-compat/bsd-arc4random.c b/openbsd-compat/bsd-arc4random.c
index d45fb182a..8bf31e5d3 100644
--- a/openbsd-compat/bsd-arc4random.c
+++ b/openbsd-compat/bsd-arc4random.c
@@ -82,3 +82,68 @@ arc4random_stir(void)
82 rc4_ready = REKEY_BYTES; 82 rc4_ready = REKEY_BYTES;
83} 83}
84#endif /* !HAVE_ARC4RANDOM */ 84#endif /* !HAVE_ARC4RANDOM */
85
86#ifndef ARC4RANDOM_BUF
87void
88arc4random_buf(void *_buf, size_t n)
89{
90 size_t i;
91 u_int32_t r;
92 char *buf = (char *)_buf;
93
94 for (i = 0; i < n; i++) {
95 if (i % 4 == 0)
96 r = arc4random();
97 buf[i] = r & 0xff;
98 r >>= 8;
99 }
100 i = r = 0;
101}
102#endif /* !HAVE_ARC4RANDOM_BUF */
103
104#ifndef ARC4RANDOM_UNIFORM
105/*
106 * Calculate a uniformly distributed random number less than upper_bound
107 * avoiding "modulo bias".
108 *
109 * Uniformity is achieved by generating new random numbers until the one
110 * returned is outside the range [0, 2**32 % upper_bound). This
111 * guarantees the selected random number will be inside
112 * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
113 * after reduction modulo upper_bound.
114 */
115u_int32_t
116arc4random_uniform(u_int32_t upper_bound)
117{
118 u_int32_t r, min;
119
120 if (upper_bound < 2)
121 return 0;
122
123#if (ULONG_MAX > 0xffffffffUL)
124 min = 0x100000000UL % upper_bound;
125#else
126 /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
127 if (upper_bound > 0x80000000)
128 min = 1 + ~upper_bound; /* 2**32 - upper_bound */
129 else {
130 /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
131 min = ((0xffffffff - (upper_bound << 2)) + 1) % upper_bound;
132 }
133#endif
134
135 /*
136 * This could theoretically loop forever but each retry has
137 * p > 0.5 (worst case, usually far better) of selecting a
138 * number inside the range we need, so it should rarely need
139 * to re-roll.
140 */
141 for (;;) {
142 r = arc4random();
143 if (r >= min)
144 break;
145 }
146
147 return r % upper_bound;
148}
149#endif /* !HAVE_ARC4RANDOM_UNIFORM */