1 /*
2  *  Copyright (c) 2019, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file provides an implementation of OpenThread random number generation manager class.
32  */
33 
34 #include "random_manager.hpp"
35 
36 #include <openthread/platform/entropy.h>
37 
38 #if !OPENTHREAD_RADIO
39 #include <mbedtls/entropy_poll.h>
40 #endif
41 
42 #include "common/code_utils.hpp"
43 #include "common/debug.hpp"
44 #include "common/logging.hpp"
45 #include "common/random.hpp"
46 #include "crypto/mbedtls.hpp"
47 
48 namespace ot {
49 
50 uint16_t                     RandomManager::sInitCount = 0;
51 RandomManager::NonCryptoPrng RandomManager::sPrng;
52 
53 #if !OPENTHREAD_RADIO
54 RandomManager::Entropy       RandomManager::sEntropy;
55 RandomManager::CryptoCtrDrbg RandomManager::sCtrDrbg;
56 #endif
57 
RandomManager(void)58 RandomManager::RandomManager(void)
59 {
60     uint32_t seed;
61     Error    error;
62 
63     OT_UNUSED_VARIABLE(error);
64 
65     OT_ASSERT(sInitCount < 0xffff);
66 
67     VerifyOrExit(sInitCount == 0);
68 
69 #if !OPENTHREAD_RADIO
70     sEntropy.Init();
71     sCtrDrbg.Init();
72 
73     error = Random::Crypto::FillBuffer(reinterpret_cast<uint8_t *>(&seed), sizeof(seed));
74     OT_ASSERT(error == kErrorNone);
75 #else
76     error = otPlatEntropyGet(reinterpret_cast<uint8_t *>(&seed), sizeof(seed));
77     OT_ASSERT(error == kErrorNone);
78 #endif
79 
80     sPrng.Init(seed);
81 
82 exit:
83     sInitCount++;
84 }
85 
~RandomManager(void)86 RandomManager::~RandomManager(void)
87 {
88     OT_ASSERT(sInitCount > 0);
89 
90     sInitCount--;
91     VerifyOrExit(sInitCount == 0);
92 
93 #if !OPENTHREAD_RADIO
94     sCtrDrbg.Deinit();
95     sEntropy.Deinit();
96 #endif
97 
98 exit:
99     return;
100 }
101 
NonCryptoGetUint32(void)102 uint32_t RandomManager::NonCryptoGetUint32(void)
103 {
104     OT_ASSERT(sInitCount > 0);
105 
106     return sPrng.GetNext();
107 }
108 
109 //-------------------------------------------------------------------
110 // NonCryptoPrng
111 
Init(uint32_t aSeed)112 void RandomManager::NonCryptoPrng::Init(uint32_t aSeed)
113 {
114     // The PRNG has a cycle of length 1 for the below two initial
115     // seeds. For all other seed values the cycle is ~2^31 long.
116 
117     if ((aSeed == 0) || (aSeed == 0x7fffffff))
118     {
119         aSeed = 0x1;
120     }
121 
122     mState = aSeed;
123 }
124 
GetNext(void)125 uint32_t RandomManager::NonCryptoPrng::GetNext(void)
126 {
127     uint32_t mlcg, p, q;
128     uint64_t tmpstate;
129 
130     tmpstate = static_cast<uint64_t>(33614) * static_cast<uint64_t>(mState);
131     q        = tmpstate & 0xffffffff;
132     q        = q >> 1;
133     p        = tmpstate >> 32;
134     mlcg     = p + q;
135 
136     if (mlcg & 0x80000000)
137     {
138         mlcg &= 0x7fffffff;
139         mlcg++;
140     }
141 
142     mState = mlcg;
143 
144     return mlcg;
145 }
146 
147 #if !OPENTHREAD_RADIO
148 
149 //-------------------------------------------------------------------
150 // Entropy
151 
Init(void)152 void RandomManager::Entropy::Init(void)
153 {
154     mbedtls_entropy_init(&mEntropyContext);
155 
156 #ifndef OT_MBEDTLS_STRONG_DEFAULT_ENTROPY_PRESENT
157     mbedtls_entropy_add_source(&mEntropyContext, &RandomManager::Entropy::HandleMbedtlsEntropyPoll, nullptr,
158                                MBEDTLS_ENTROPY_MIN_HARDWARE, MBEDTLS_ENTROPY_SOURCE_STRONG);
159 #endif // OT_MBEDTLS_STRONG_DEFAULT_ENTROPY_PRESENT
160 }
161 
Deinit(void)162 void RandomManager::Entropy::Deinit(void)
163 {
164     mbedtls_entropy_free(&mEntropyContext);
165 }
166 
167 #ifndef OT_MBEDTLS_STRONG_DEFAULT_ENTROPY_PRESENT
168 
HandleMbedtlsEntropyPoll(void * aData,unsigned char * aOutput,size_t aInLen,size_t * aOutLen)169 int RandomManager::Entropy::HandleMbedtlsEntropyPoll(void *         aData,
170                                                      unsigned char *aOutput,
171                                                      size_t         aInLen,
172                                                      size_t *       aOutLen)
173 {
174     int rval = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
175 
176     SuccessOrExit(otPlatEntropyGet(reinterpret_cast<uint8_t *>(aOutput), static_cast<uint16_t>(aInLen)));
177     rval = 0;
178 
179     VerifyOrExit(aOutLen != nullptr);
180     *aOutLen = aInLen;
181 
182 exit:
183     OT_UNUSED_VARIABLE(aData);
184     return rval;
185 }
186 
187 #endif // OT_MBEDTLS_STRONG_DEFAULT_ENTROPY_PRESENT
188 
189 //-------------------------------------------------------------------
190 // CryptoCtrDrbg
191 
Init(void)192 void RandomManager::CryptoCtrDrbg::Init(void)
193 {
194     int rval;
195 
196     mbedtls_ctr_drbg_init(&mCtrDrbg);
197 
198     rval =
199         mbedtls_ctr_drbg_seed(&mCtrDrbg, mbedtls_entropy_func, RandomManager::GetMbedTlsEntropyContext(), nullptr, 0);
200 
201     if (rval != 0)
202     {
203         otLogCritMbedTls("Failed to seed the CTR DRBG");
204     }
205 
206     OT_ASSERT(rval == 0);
207 }
208 
Deinit(void)209 void RandomManager::CryptoCtrDrbg::Deinit(void)
210 {
211     mbedtls_ctr_drbg_free(&mCtrDrbg);
212 }
213 
FillBuffer(uint8_t * aBuffer,uint16_t aSize)214 Error RandomManager::CryptoCtrDrbg::FillBuffer(uint8_t *aBuffer, uint16_t aSize)
215 {
216     return ot::Crypto::MbedTls::MapError(
217         mbedtls_ctr_drbg_random(&mCtrDrbg, static_cast<unsigned char *>(aBuffer), static_cast<size_t>(aSize)));
218 }
219 
220 #endif // #if !OPENTHREAD_RADIO
221 
222 } // namespace ot
223