/* * Copyright (c) 2019, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @file * This file provides an implementation of OpenThread random number generation manager class. */ #include "random_manager.hpp" #include #if !OPENTHREAD_RADIO #include #endif #include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/logging.hpp" #include "common/random.hpp" #include "crypto/mbedtls.hpp" namespace ot { uint16_t RandomManager::sInitCount = 0; RandomManager::NonCryptoPrng RandomManager::sPrng; #if !OPENTHREAD_RADIO RandomManager::Entropy RandomManager::sEntropy; RandomManager::CryptoCtrDrbg RandomManager::sCtrDrbg; #endif RandomManager::RandomManager(void) { uint32_t seed; Error error; OT_UNUSED_VARIABLE(error); OT_ASSERT(sInitCount < 0xffff); VerifyOrExit(sInitCount == 0); #if !OPENTHREAD_RADIO sEntropy.Init(); sCtrDrbg.Init(); error = Random::Crypto::FillBuffer(reinterpret_cast(&seed), sizeof(seed)); OT_ASSERT(error == kErrorNone); #else error = otPlatEntropyGet(reinterpret_cast(&seed), sizeof(seed)); OT_ASSERT(error == kErrorNone); #endif sPrng.Init(seed); exit: sInitCount++; } RandomManager::~RandomManager(void) { OT_ASSERT(sInitCount > 0); sInitCount--; VerifyOrExit(sInitCount == 0); #if !OPENTHREAD_RADIO sCtrDrbg.Deinit(); sEntropy.Deinit(); #endif exit: return; } uint32_t RandomManager::NonCryptoGetUint32(void) { OT_ASSERT(sInitCount > 0); return sPrng.GetNext(); } //------------------------------------------------------------------- // NonCryptoPrng void RandomManager::NonCryptoPrng::Init(uint32_t aSeed) { // The PRNG has a cycle of length 1 for the below two initial // seeds. For all other seed values the cycle is ~2^31 long. if ((aSeed == 0) || (aSeed == 0x7fffffff)) { aSeed = 0x1; } mState = aSeed; } uint32_t RandomManager::NonCryptoPrng::GetNext(void) { uint32_t mlcg, p, q; uint64_t tmpstate; tmpstate = static_cast(33614) * static_cast(mState); q = tmpstate & 0xffffffff; q = q >> 1; p = tmpstate >> 32; mlcg = p + q; if (mlcg & 0x80000000) { mlcg &= 0x7fffffff; mlcg++; } mState = mlcg; return mlcg; } #if !OPENTHREAD_RADIO //------------------------------------------------------------------- // Entropy void RandomManager::Entropy::Init(void) { mbedtls_entropy_init(&mEntropyContext); #ifndef OT_MBEDTLS_STRONG_DEFAULT_ENTROPY_PRESENT mbedtls_entropy_add_source(&mEntropyContext, &RandomManager::Entropy::HandleMbedtlsEntropyPoll, nullptr, MBEDTLS_ENTROPY_MIN_HARDWARE, MBEDTLS_ENTROPY_SOURCE_STRONG); #endif // OT_MBEDTLS_STRONG_DEFAULT_ENTROPY_PRESENT } void RandomManager::Entropy::Deinit(void) { mbedtls_entropy_free(&mEntropyContext); } #ifndef OT_MBEDTLS_STRONG_DEFAULT_ENTROPY_PRESENT int RandomManager::Entropy::HandleMbedtlsEntropyPoll(void * aData, unsigned char *aOutput, size_t aInLen, size_t * aOutLen) { int rval = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; SuccessOrExit(otPlatEntropyGet(reinterpret_cast(aOutput), static_cast(aInLen))); rval = 0; VerifyOrExit(aOutLen != nullptr); *aOutLen = aInLen; exit: OT_UNUSED_VARIABLE(aData); return rval; } #endif // OT_MBEDTLS_STRONG_DEFAULT_ENTROPY_PRESENT //------------------------------------------------------------------- // CryptoCtrDrbg void RandomManager::CryptoCtrDrbg::Init(void) { int rval; mbedtls_ctr_drbg_init(&mCtrDrbg); rval = mbedtls_ctr_drbg_seed(&mCtrDrbg, mbedtls_entropy_func, RandomManager::GetMbedTlsEntropyContext(), nullptr, 0); if (rval != 0) { otLogCritMbedTls("Failed to seed the CTR DRBG"); } OT_ASSERT(rval == 0); } void RandomManager::CryptoCtrDrbg::Deinit(void) { mbedtls_ctr_drbg_free(&mCtrDrbg); } Error RandomManager::CryptoCtrDrbg::FillBuffer(uint8_t *aBuffer, uint16_t aSize) { return ot::Crypto::MbedTls::MapError( mbedtls_ctr_drbg_random(&mCtrDrbg, static_cast(aBuffer), static_cast(aSize))); } #endif // #if !OPENTHREAD_RADIO } // namespace ot