VirtualBox

Ignore:
Timestamp:
Aug 20, 2008 8:48:52 PM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
35074
Message:

iprt: Implemented the /dev/urandom base random generator as a RTRAND opaque. Made the simple RTRand API just serve as a wrapper using the RTRandAdv API with a global RTRAND handle.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/rand/rand.cpp

    r11172 r11523  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Random Number
     3 * IPRT - Random Numbers.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2007 Sun Microsystems, Inc.
     7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3939#include <iprt/assert.h>
    4040#include <iprt/thread.h>
     41#include <iprt/once.h>
    4142#include "internal/rand.h"
    4243
     
    4546*   Global Variables                                                           *
    4647*******************************************************************************/
    47 /** Lazy init. */
    48 static volatile bool    g_fInitialized = false;
    49 /** The context variable for the fallback path. */
    50 static uint32_t         g_u32Ctx;
    51 
    52 
    53 /*******************************************************************************
    54 *   Internal Functions                                                         *
    55 *******************************************************************************/
    56 static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx);
     48/** For lazily initializating of the random generator. */
     49static RTONCE g_rtRandOnce = RTONCE_INITIALIZER;
     50/** The default random generator. */
     51static RTRAND g_hRand = NIL_RTRAND;
    5752
    5853
    5954/**
    60  * Lazy initialization of the native and fallback random byte sources.
     55 * Perform lazy initialization.
    6156 *
     57 * @returns IPRT status code.
     58 * @param   pvUser1     Ignored.
     59 * @param   pvUser2     Ignored.
    6260 */
    63 static void rtRandLazyInit(void)
     61static DECLCALLBACK(int) rtRandInitOnce(void *pvUser1, void *pvUser2)
    6462{
    65     /*
    66      * Seed the fallback random code.
    67      */
    68     g_u32Ctx = (uint32_t)(ASMReadTSC() >> 8);
     63    NOREF(pvUser1);
     64    NOREF(pvUser2);
    6965
    70     /*
    71      * Call host specific init.
    72      */
    73     rtRandLazyInitNative();
    74     g_fInitialized = true;
     66    RTRAND hRand;
     67    int rc = RTRandAdvCreateNonPseudo(&hRand);
     68    if (RT_FAILURE(rc))
     69        rc = RTRandAdvCreateParkMiller(&hRand);
     70    if (RT_SUCCESS(rc))
     71    {
     72        RTRandAdvSeed(hRand, ASMReadTSC() >> 8);
     73        g_hRand = hRand;
     74    }
     75    else
     76        AssertRC(rc);
     77
     78    return rc;
    7579}
    7680
    7781
    78 /**
    79  * Internal wrapper for the native and generic random byte methods.
    80  *
    81  * @param   pv  Where to store the random bytes.
    82  * @param   cb  Number of bytes to generate.
    83  */
    84 static void rtRandGenBytes(void *pv, size_t cb)
     82RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW
    8583{
    86     Assert(cb);
    87     if (RT_UNLIKELY(!g_fInitialized))
    88         rtRandLazyInit();
    89 
    90     int rc = rtRandGenBytesNative(pv, cb);
    91     if (RT_FAILURE(rc))
    92         rtRandGenBytesFallback(pv, cb);
     84    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     85    RTRandAdvBytes(g_hRand, pv, cb);
    9386}
    9487
    9588
    96 /**
    97  * Fills a buffer with random bytes.
    98  *
    99  * @param   pv  Where to store the random bytes.
    100  * @param   cb  Number of bytes to generate.
    101  */
    102 RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW
     89RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW
    10390{
    104     if (cb)
    105         rtRandGenBytes(pv, cb);
     91    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     92    return RTRandAdvU32Ex(g_hRand, u32First, u32Last);
    10693}
    10794
    10895
    109 /**
    110  * Generate a 32-bit unsigned random number in the set [u32First..u32Last].
    111  *
    112  * @returns The random number.
    113  * @param   u32First    First number in the set.
    114  * @param   u32Last     Last number in the set.
    115  */
    116 RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW
     96RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW
    11797{
    118     union
    119     {
    120         uint32_t    off;
    121         uint8_t     ab[5];
    122     } u;
    123 
    124     const uint32_t offLast = u32Last - u32First;
    125     if (offLast == UINT32_MAX)
    126         /* get 4 random bytes and return them raw. */
    127         rtRandGenBytes(&u.ab[0], sizeof(u.off));
    128     else if (!(offLast & UINT32_C(0xf0000000)))
    129     {
    130         /* get 4 random bytes and do simple squeeze. */
    131         rtRandGenBytes(&u.ab[0], sizeof(u.off));
    132         u.off %= offLast + 1;
    133         u.off += u32First;
    134     }
    135     else
    136     {
    137         /* get 5 random bytes and do shifted squeeze. (this ain't perfect) */
    138         rtRandGenBytes(&u.ab[0], sizeof(u.ab));
    139         u.off %= (offLast >> 4) + 1;
    140         u.off <<= 4;
    141         u.off |= u.ab[4] & 0xf;
    142         if (u.off > offLast)
    143             u.off = offLast;
    144         u.off += u32First;
    145     }
    146     return u.off;
     98    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     99    return RTRandAdvU32(g_hRand);
    147100}
    148101
    149102
    150 /**
    151  * Generate a 32-bit unsigned random number.
    152  *
    153  * @returns The random number.
    154  */
    155 RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW
     103RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW
    156104{
    157     return RTRandU32Ex(0, UINT32_MAX);
     105    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     106    return RTRandAdvS32Ex(g_hRand, i32First, i32Last);
    158107}
    159108
    160109
    161 /**
    162  * Generate a 32-bit signed random number in the set [i32First..i32Last].
    163  *
    164  * @returns The random number.
    165  * @param   i32First    First number in the set.
    166  * @param   i32Last     Last number in the set.
    167  */
    168 RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW
     110RTDECL(int32_t) RTRandS32(void) RT_NO_THROW
    169111{
    170     if (i32First == INT32_MIN && i32Last == INT32_MAX)
    171         return (int32_t)RTRandU32Ex(0, UINT32_MAX);
    172     return RTRandU32Ex(0, i32Last - i32First) + i32First;
     112    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     113    return RTRandAdvS32(g_hRand);
    173114}
    174115
    175116
    176 /**
    177  * Generate a 32-bit signed random number.
    178  *
    179  * @returns The random number.
    180  */
    181 RTDECL(int32_t) RTRandS32(void) RT_NO_THROW
     117RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW
    182118{
    183     return (int32_t)RTRandU32Ex(0, UINT32_MAX);
     119    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     120    return RTRandAdvU64Ex(g_hRand, u64First, u64Last);
    184121}
    185122
    186123
    187 /**
    188  * Generate a 64-bit unsigned random number in the set [u64First..u64Last].
    189  *
    190  * @returns The random number.
    191  * @param   u64First    First number in the set.
    192  * @param   u64Last     Last number in the set.
    193  */
    194 RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW
     124RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW
    195125{
    196     union
    197     {
    198         uint64_t    off;
    199         uint32_t    off32;
    200         uint8_t     ab[9];
    201     } u;
    202 
    203     const uint64_t offLast = u64Last - u64First;
    204     if (offLast == UINT64_MAX)
    205         /* get 8 random bytes and return them raw. */
    206         rtRandGenBytes(&u.ab[0], sizeof(u.off));
    207     else if (!(offLast & UINT64_C(0xf000000000000000)))
    208     {
    209         /* get 8 random bytes and do simple squeeze. */
    210         rtRandGenBytes(&u.ab[0], sizeof(u.off));
    211         u.off %= offLast + 1;
    212         u.off += u64First;
    213     }
    214     else
    215     {
    216         /* get 9 random bytes and do shifted squeeze. (this ain't perfect) */
    217         rtRandGenBytes(&u.ab[0], sizeof(u.ab));
    218         u.off %= (offLast >> 4) + 1;
    219         u.off <<= 4;
    220         u.off |= u.ab[8] & 0xf;
    221         if (u.off > offLast)
    222             u.off = offLast;
    223         u.off += u64First;
    224     }
    225     return u.off;
     126    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     127    return RTRandAdvU64(g_hRand);
    226128}
    227129
    228130
    229 /**
    230  * Generate a 64-bit unsigned random number.
    231  *
    232  * @returns The random number.
    233  */
    234 RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW
     131RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW
    235132{
    236     return RTRandU64Ex(0, UINT64_MAX);
     133    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     134    return RTRandAdvS64Ex(g_hRand, i64First, i64Last);
    237135}
    238136
    239137
    240 /**
    241  * Generate a 64-bit signed random number in the set [i64First..i64Last].
    242  *
    243  * @returns The random number.
    244  * @param   i64First    First number in the set.
    245  * @param   i64Last     Last number in the set.
    246  */
    247 RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW
     138RTDECL(int64_t) RTRandS64(void) RT_NO_THROW
    248139{
    249     if (i64First == INT64_MIN && i64Last == INT64_MAX)
    250         return (int64_t)RTRandU64Ex(0, UINT64_MAX);
    251     return (int64_t)RTRandU64Ex(0, i64Last - i64First) + i64First;
     140    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     141    return RTRandAdvS32(g_hRand);
    252142}
    253143
    254 
    255 /**
    256  * Generate a 64-bit signed random number.
    257  *
    258  * @returns The random number.
    259  */
    260 RTDECL(int64_t) RTRandS64(void) RT_NO_THROW
    261 {
    262     return (int64_t)RTRandU64Ex(0, UINT64_MAX);
    263 }
    264 
    265 
    266 /**
    267  * Fallback random byte source.
    268  *
    269  * @param   pv  Where to store the random bytes.
    270  * @param   cb  Number of bytes to generate.
    271  */
    272 void rtRandGenBytesFallback(void *pv, size_t cb) RT_NO_THROW
    273 {
    274     uint64_t u64Last = 0;
    275     uint8_t *pb = (uint8_t *)pv;
    276     for (unsigned i = 0;; i++)
    277     {
    278         uint32_t u32 = rtRandGenBytesFallbackU31(&g_u32Ctx);
    279 
    280         *pb++ = (uint8_t)u32;
    281         if (!--cb)
    282             break;
    283 
    284         u32 >>= 8;
    285         *pb++ = (uint8_t)u32;
    286         if (!--cb)
    287             break;
    288 
    289         u32 >>= 8;
    290         *pb++ = (uint8_t)u32;
    291         if (!--cb)
    292             break;
    293 
    294         /*
    295          * Is this really a good idea? Looks like we cannot
    296          * quite trust the lower bits here for instance...
    297          */
    298         if (!(i % 3))
    299         {
    300             uint64_t u64 = ASMReadTSC();
    301             uint64_t u64Delta = u64 - u64Last;
    302             if (u64Delta > 0xff)
    303             {
    304                 u32 >>= 8;
    305                 *pb++ = ((uint8_t)u64 >> 5) | (u32 << 3);
    306                 if (!--cb)
    307                     break;
    308                 u64Last = u64;
    309             }
    310         }
    311     }
    312 }
    313 
    314 
    315 /*-
    316  * Copyright (c) 1990, 1993
    317  *      The Regents of the University of California.  All rights reserved.
    318  *
    319  * Redistribution and use in source and binary forms, with or without
    320  * modification, are permitted provided that the following conditions
    321  * are met:
    322  * 1. Redistributions of source code must retain the above copyright
    323  *    notice, this list of conditions and the following disclaimer.
    324  * 2. Redistributions in binary form must reproduce the above copyright
    325  *    notice, this list of conditions and the following disclaimer in the
    326  *    documentation and/or other materials provided with the distribution.
    327  * 4. Neither the name of the University nor the names of its contributors
    328  *    may be used to endorse or promote products derived from this software
    329  *    without specific prior written permission.
    330  *
    331  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    332  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    333  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    334  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    335  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    336  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    337  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    338  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    339  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    340  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    341  * SUCH DAMAGE.
    342  */
    343 
    344 /* The core of:
    345 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/stdlib/rand.c,v 1.16 2007/01/09 00:28:10 imp Exp $");
    346 */
    347 
    348 /**
    349  * Generates an unsigned 31 bit pseudo random number.
    350  *
    351  * @returns pseudo random number.
    352  * @param   pCtx    The context.
    353  */
    354 static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx)
    355 {
    356     /*
    357      * Compute x = (7^5 * x) mod (2^31 - 1)
    358      * without overflowing 31 bits:
    359      *      (2^31 - 1) = 127773 * (7^5) + 2836
    360      *
    361      * From "Random number generators: good ones are hard to find",  Park and
    362      * Miller, Communications of the ACM, vol. 31, no. 10, October 1988, p. 1195.
    363      */
    364     uint32_t Ctx = *pCtx;
    365     if (!Ctx) /* must not be zero. */
    366         Ctx = 0x20070212;
    367     uint32_t Hi = Ctx / 127773;
    368     uint32_t Lo = Ctx % 127773;
    369     int32_t x = 16807 * Lo  -  2836 * Hi;
    370     if (x < 0)
    371         x += INT32_MAX;
    372     *pCtx = x;
    373     return x % INT32_MAX;
    374 }
    375 
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette