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