// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. #include "cdm_random.h" #include #include #include "log.h" // This type alias is for convenience. using CdmRandomLock = std::unique_lock; namespace wvcdm { namespace { // More information about C++11's random number generators can be found // from the introductory paper https://isocpp.org/files/papers/n3551.pdf // Attemps to get random data in a device specific manner. If the device // does not support true random data, then a pseudo-random sequence might // be used instead. The exact behaviour depends on the compiler and // platform combination. unsigned int GetDeviceRandomSeed() { static std::random_device rdev; static std::mutex rdev_mutex; CdmRandomLock rdev_lock(rdev_mutex); return rdev(); } } // namespace // CdmRandomGenerator. CdmRandomGenerator::CdmRandomGenerator() : generator_(GetDeviceRandomSeed()) {} void CdmRandomGenerator::Seed() { CdmRandomLock lock(generator_lock_); generator_.seed(GetDeviceRandomSeed()); } void CdmRandomGenerator::Seed(unsigned int s) { CdmRandomLock lock(generator_lock_); generator_.seed(s); } unsigned int CdmRandomGenerator::Rand() { CdmRandomLock lock(generator_lock_); std::uniform_int_distribution dist(0, RAND_MAX); return dist(generator_); } uint64_t CdmRandomGenerator::RandomInRange(uint64_t lower, uint64_t upper) { if (lower == upper) { return lower; } CdmRandomLock lock(generator_lock_); if (lower > upper) { LOGW( "Lower bound is larger than upper bound, swapping bounds: " "lower = %llu, upper = %llu", // Casting to insure this will work on 32-bit systems. static_cast(lower), static_cast(upper)); std::swap(lower, upper); } std::uniform_int_distribution dist(lower, upper); return dist(generator_); } std::string CdmRandomGenerator::RandomData(size_t length) { if (length > kMaxRandomDataLength) { LOGE("Maximum random data length exceeded: length = %zu, max_length = %zu", length, kMaxRandomDataLength); return std::string(); } CdmRandomLock lock(generator_lock_); std::uniform_int_distribution dist; // Range of [0, 255]. std::string random_data(length, '\0'); std::generate(random_data.begin(), random_data.end(), [&]() { return dist(generator_); }); return random_data; } bool CdmRandomGenerator::RandomBool() { CdmRandomLock lock(generator_lock_); std::bernoulli_distribution dist; // 50/50. return dist(generator_); } // CdmRandom. // static CdmRandomGenerator* CdmRandom::GetInstance() { static std::mutex g_instance_lock; static CdmRandomGenerator* g_instance = nullptr; CdmRandomLock lock(g_instance_lock); if (g_instance == nullptr) { LOGV("Initalizing CDM random number generator"); g_instance = new CdmRandomGenerator(GetDeviceRandomSeed()); } return g_instance; } } // namespace wvcdm