// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. #ifndef WVCDM_CORE_CDM_RANDOM_H_ #define WVCDM_CORE_CDM_RANDOM_H_ #include #include #include namespace wvutil { // CdmRandomGenerator is a thread safe, pseudo-random number generator. // It's purpose is to simplified interface for C++11's library. // Some of the methods use a "device specific" random seed, if the // compiler/device does not support device specific randomizers, then the // actual value supplied may not be random. The generator is designed to // meet the C++ named requirement UniformRandomBitGenerator to allow it to // be used with standard library functions / class which are designed to // work with the standard library generators. class CdmRandomGenerator { public: // Result type of operator(). using result_type = unsigned int; // Inclusive boundaries of operator(). static constexpr unsigned int min() { return 0; } static constexpr unsigned int max() { return RAND_MAX; } // The maximum number of bytes that can be generated at once for // `RandomData()`. static constexpr size_t kMaxRandomDataLength = 8192; // 8 kB // Initializes the pseudo-random generator with a value from a device // specific random number generator. CdmRandomGenerator(); // Initializes the pseudo-random generator with the specified seed value. explicit CdmRandomGenerator(unsigned int seed) : generator_(seed) {} // All of these methods are thread-safe. // Seeds the pseudo-random generator with a value from a device specific // random number generator. void Seed(); // Seeds the pseudo-random generator with the specified seed value. // This is somewhat similar to `srand()` from the C standard library; // except that the sequence generated from successive calls to `Rand()` // will not necessarily be the same as they would be from the // standard library `rand()`. This is due to the underlying pseudo-random // generator that is used. void Seed(unsigned int seed); // Returns a pseudo-random integer. // This is similar to `rand()` from the C standard library. The integer // returned is in the range of [min(), max()]. unsigned int Rand(); // Allows for RNG to be callable. unsigned int operator()() { return Rand(); } // Returns a pseudo-random integer within the provided inclusive range. uint64_t RandomInRange(uint64_t lower, uint64_t upper); uint64_t RandomInRange(uint64_t upper) { return RandomInRange(0, upper); } // Returns a byte string containing randomized bytes of the specified // length. // If |length| is greater than |CdmRandomGenerator::kMaxRandomDataLength|, // then an error is logged and an empty string is returned. std::string RandomData(size_t length); // Random true/false using Bernoulli distribution of equal probability. bool RandomBool(); private: // Mutex is used to lock the object, and allowing it to be used // concurrently in different threads. std::mutex generator_lock_; // The `default_random_engine` depends on the compiler used and // potentially its version. This is important to know if you need to // create reproducible tests between platforms. std::default_random_engine generator_; }; // Provides a static interface to a process-wide instance of // CdmRandomGenerator. class CdmRandom { public: static unsigned int Rand() { return GetInstance()->Rand(); } static uint64_t RandomInRange(uint64_t lower, uint64_t upper) { return GetInstance()->RandomInRange(lower, upper); } static uint64_t RandomInRange(uint64_t upper) { return GetInstance()->RandomInRange(upper); } static std::string RandomData(size_t length) { return GetInstance()->RandomData(length); } static bool RandomBool() { return GetInstance()->RandomBool(); } private: // These are intended to be used by tests if needed. static void Seed(unsigned int seed) { GetInstance()->Seed(seed); } static void Seed() { GetInstance()->Seed(); } // Returns the process-wide instance of CdmRandomGenerator. // It the global instance has not yet been created, then a new instance // is created using a device-specific random seed. static CdmRandomGenerator* GetInstance(); }; } // namespace wvutil #endif // WVCDM_CORE_CDM_RANDOM_H_