1 /* $Id: rand.cpp 25033 2007-10-04 07:21:02Z frank $ */
3 * innotek Portable Runtime - Random Number
7 * Copyright (C) 2006-2007 innotek GmbH
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
19 /*******************************************************************************
21 *******************************************************************************/
25 #include "const_defines.h"
26 #include "func_defines.h"
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <sys/fcntl.h>
34 # include <sys/time.h>
37 /*******************************************************************************
39 *******************************************************************************/
41 static volatile bool g_fInitialized
= false;
42 /** The context variable for the fallback path. */
43 static uint32_t g_u32Ctx
;
44 /** File handle of /dev/random. */
45 static int g_fhDevRandom
= -1;
48 /*******************************************************************************
49 * Internal Functions *
50 *******************************************************************************/
51 static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx
);
55 * Lazy initialization of the native and fallback random byte sources.
58 static void rtRandLazyInit(void)
61 * Seed the fallback random code.
63 g_u32Ctx
= (uint32_t)(ASMReadTSC() >> 8);
66 * Call host specific init.
68 rtRandLazyInitNative();
69 g_fInitialized
= true;
74 * Internal wrapper for the native and generic random byte methods.
76 * @param pv Where to store the random bytes.
77 * @param cb Number of bytes to generate.
79 static void rtRandGenBytes(void *pv
, size_t cb
)
82 if (RT_UNLIKELY(!g_fInitialized
))
85 int rc
= rtRandGenBytesNative(pv
, cb
);
87 rtRandGenBytesFallback(pv
, cb
);
92 * Fills a buffer with random bytes.
94 * @param pv Where to store the random bytes.
95 * @param cb Number of bytes to generate.
97 void RTRandBytes(void *pv
, size_t cb
)
100 rtRandGenBytes(pv
, cb
);
105 * Generate a 32-bit signed random number in the set [i32First..i32Last].
107 * @returns The random number.
108 * @param i32First First number in the set.
109 * @param i32Last Last number in the set.
111 int32_t RTRandS32Ex(int32_t i32First
, int32_t i32Last
)
113 /* get 4 random bytes. */
119 rtRandGenBytes(&u
.ab
, sizeof(u
));
122 /* squeeze it into the requested range. */
123 uint32_t offLast
= i32Last
- i32First
;
129 } while (u
.off
> offLast
);
131 return i32First
+ u
.off
;
136 * Generate a 32-bit signed random number.
138 * @returns The random number.
140 int32_t RTRandS32(void)
142 return RTRandS32Ex(INT32_MIN
, INT32_MAX
);
147 * Generate a 32-bit unsigned random number in the set [u32First..u32Last].
149 * @returns The random number.
150 * @param u32First First number in the set.
151 * @param u32Last Last number in the set.
153 uint32_t RTRandU32Ex(uint32_t u32First
, uint32_t u32Last
)
155 /* get 4 random bytes. */
161 rtRandGenBytes(&u
.ab
, sizeof(u
));
164 /* squeeze it into the requested range. */
165 const uint32_t offLast
= u32Last
- u32First
;
171 } while (u
.off
> offLast
);
173 return u32First
+ u
.off
;
178 * Generate a 32-bit unsigned random number.
180 * @returns The random number.
182 uint32_t RTRandU32(void)
184 return RTRandU32Ex(0, UINT32_MAX
);
189 * Generate a 32-bit signed random number in the set [i32First..i32Last].
191 * @returns The random number.
192 * @param i32First First number in the set.
193 * @param i32Last Last number in the set.
195 int64_t RTRandS64Ex(int64_t i64First
, int64_t i64Last
)
197 /* get 8 random bytes. */
203 rtRandGenBytes(&u
.ab
, sizeof(u
));
205 /* squeeze it into the requested range. */
206 uint64_t offLast
= i64Last
- i64First
;
212 } while (u
.off
> offLast
);
214 return i64First
+ u
.off
;
219 * Generate a 64-bit signed random number.
221 * @returns The random number.
223 int64_t RTRandS64(void)
225 return RTRandS64Ex(INT64_MIN
, INT64_MAX
);
230 * Generate a 64-bit unsigned random number in the set [u64First..u64Last].
232 * @returns The random number.
233 * @param u64First First number in the set.
234 * @param u64Last Last number in the set.
236 uint64_t RTRandU64Ex(uint64_t u64First
, uint64_t u64Last
)
238 /* get 8 random bytes. */
244 rtRandGenBytes(&u
.ab
, sizeof(u
));
246 /* squeeze it into the requested range. */
247 const uint64_t offLast
= u64Last
- u64First
;
253 } while (u
.off
> offLast
);
255 return u64First
+ u
.off
;
260 * Generate a 64-bit unsigned random number.
262 * @returns The random number.
264 uint64_t RTRandU64(void)
266 return RTRandU64Ex(0, UINT64_MAX
);
271 * Fallback random byte source.
273 * @param pv Where to store the random bytes.
274 * @param cb Number of bytes to generate.
276 void rtRandGenBytesFallback(void *pv
, size_t cb
)
278 uint8_t *pb
= (uint8_t *)pv
;
279 for (unsigned i
= 0;; i
++)
281 uint32_t u32
= rtRandGenBytesFallbackU31(&g_u32Ctx
);
283 *pb
++ = (uint8_t)u32
;
288 *pb
++ = (uint8_t)u32
;
293 *pb
++ = (uint8_t)u32
;
297 /* Is this really a good idea? */
302 *pb++ = (uint8_t)ASMReadTSC();
312 * Copyright (c) 1990, 1993
313 * The Regents of the University of California. All rights reserved.
315 * Redistribution and use in source and binary forms, with or without
316 * modification, are permitted provided that the following conditions
318 * 1. Redistributions of source code must retain the above copyright
319 * notice, this list of conditions and the following disclaimer.
320 * 2. Redistributions in binary form must reproduce the above copyright
321 * notice, this list of conditions and the following disclaimer in the
322 * documentation and/or other materials provided with the distribution.
323 * 4. Neither the name of the University nor the names of its contributors
324 * may be used to endorse or promote products derived from this software
325 * without specific prior written permission.
327 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
328 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
329 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
330 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
331 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
332 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
333 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
334 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
335 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
336 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/stdlib/rand.c,v 1.16 2007/01/09 00:28:10 imp Exp $");
345 * Generates an unsigned 31 bit pseudo random number.
347 * @returns pseudo random number.
348 * @param pCtx The context.
350 static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx
)
353 * Compute x = (7^5 * x) mod (2^31 - 1)
354 * without overflowing 31 bits:
355 * (2^31 - 1) = 127773 * (7^5) + 2836
357 * From "Random number generators: good ones are hard to find", Park and
358 * Miller, Communications of the ACM, vol. 31, no. 10, October 1988, p. 1195.
360 uint32_t Ctx
= *pCtx
;
361 if (!Ctx
) /* must not be zero. */
363 uint32_t Hi
= Ctx
/ 127773;
364 uint32_t Lo
= Ctx
% 127773;
365 int32_t x
= 16807 * Lo
- 2836 * Hi
;
369 return x
% INT32_MAX
;
372 void rtRandLazyInitNative(void)
374 if (g_fhDevRandom
!= -1)
377 int fh
= open("/dev/urandom", O_RDONLY
);
379 fh
= open("/dev/random", O_RDONLY
| O_NONBLOCK
);
382 fcntl(fh
, F_SETFD
, FD_CLOEXEC
);
388 int rtRandGenBytesNative(void *pv
, size_t cb
)
390 int fh
= g_fhDevRandom
;
392 return VERR_NOT_SUPPORTED
;
394 ssize_t cbRead
= read(fh
, pv
, cb
);
395 if ((size_t)cbRead
!= cb
)
398 * Use the fallback for the remainder if /dev/urandom / /dev/random
402 rtRandGenBytesFallback(pv
, cb
);
405 AssertRelease((size_t)cbRead
< cb
);
406 rtRandGenBytesFallback((uint8_t *)pv
+ cbRead
, cb
- cbRead
);