/* $OpenBSD: arc4random_uniform.c,v 1.2 2015/09/13 08:31:47 guenther Exp $ */12/*3* SPDX-License-Identifier: ISC4*5* Copyright (c) 2008, Damien Miller <[email protected]>6*7* Permission to use, copy, modify, and distribute this software for any8* purpose with or without fee is hereby granted, provided that the above9* copyright notice and this permission notice appear in all copies.10*11* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES12* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF13* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR14* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES15* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN16* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF17* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.18*/1920#include <config.h>2122#ifndef HAVE_ARC4RANDOM_UNIFORM2324#include <stdlib.h>25#if defined(HAVE_STDINT_H)26# include <stdint.h>27#elif defined(HAVE_INTTYPES_H)28# include <inttypes.h>29#endif3031#include <sudo_compat.h>32#include <sudo_rand.h>3334/*35* Calculate a uniformly distributed random number less than upper_bound36* avoiding "modulo bias".37*38* Uniformity is achieved by generating new random numbers until the one39* returned is outside the range [0, 2**32 % upper_bound). This40* guarantees the selected random number will be inside41* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)42* after reduction modulo upper_bound.43*/44uint32_t45sudo_arc4random_uniform(uint32_t upper_bound)46{47uint32_t r, min;4849if (upper_bound < 2)50return 0;5152/* 2**32 % x == (2**32 - x) % x */53min = -upper_bound % upper_bound;5455/*56* This could theoretically loop forever but each retry has57* p > 0.5 (worst case, usually far better) of selecting a58* number inside the range we need, so it should rarely need59* to re-roll.60*/61for (;;) {62r = arc4random();63if (r >= min)64break;65}6667return r % upper_bound;68}6970#endif /* HAVE_ARC4RANDOM_UNIFORM */717273