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.hpp"
35
36 #include <openthread/platform/entropy.h>
37
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40
41 namespace ot {
42 namespace Random {
43
44 uint16_t Manager::sInitCount = 0;
45 Manager::NonCryptoPrng Manager::sPrng;
46
Manager(void)47 Manager::Manager(void)
48 {
49 uint32_t seed;
50
51 OT_ASSERT(sInitCount < 0xffff);
52
53 VerifyOrExit(sInitCount == 0);
54
55 #if !OPENTHREAD_RADIO
56 otPlatCryptoRandomInit();
57 SuccessOrAssert(Random::Crypto::Fill(seed));
58 #else
59 SuccessOrAssert(otPlatEntropyGet(reinterpret_cast<uint8_t *>(&seed), sizeof(seed)));
60 #endif
61
62 sPrng.Init(seed);
63
64 exit:
65 sInitCount++;
66 }
67
~Manager(void)68 Manager::~Manager(void)
69 {
70 OT_ASSERT(sInitCount > 0);
71
72 sInitCount--;
73 VerifyOrExit(sInitCount == 0);
74
75 #if !OPENTHREAD_RADIO
76 otPlatCryptoRandomDeinit();
77 #endif
78
79 exit:
80 return;
81 }
82
NonCryptoGetUint32(void)83 uint32_t Manager::NonCryptoGetUint32(void)
84 {
85 OT_ASSERT(sInitCount > 0);
86
87 return sPrng.GetNext();
88 }
89
90 //-------------------------------------------------------------------
91 // NonCryptoPrng
92
Init(uint32_t aSeed)93 void Manager::NonCryptoPrng::Init(uint32_t aSeed)
94 {
95 // The PRNG has a cycle of length 1 for the below two initial
96 // seeds. For all other seed values the cycle is ~2^31 long.
97
98 if ((aSeed == 0) || (aSeed == 0x7fffffff))
99 {
100 aSeed = 0x1;
101 }
102
103 mState = aSeed;
104 }
105
GetNext(void)106 uint32_t Manager::NonCryptoPrng::GetNext(void)
107 {
108 uint32_t mlcg, p, q;
109 uint64_t tmpstate;
110
111 tmpstate = static_cast<uint64_t>(33614) * static_cast<uint64_t>(mState);
112 q = tmpstate & 0xffffffff;
113 q = q >> 1;
114 p = tmpstate >> 32;
115 mlcg = p + q;
116
117 if (mlcg & 0x80000000)
118 {
119 mlcg &= 0x7fffffff;
120 mlcg++;
121 }
122
123 mState = mlcg;
124
125 return mlcg;
126 }
127
128 //-------------------------------------------------------------------
129
130 namespace NonCrypto {
131
GetUint8InRange(uint8_t aMin,uint8_t aMax)132 uint8_t GetUint8InRange(uint8_t aMin, uint8_t aMax)
133 {
134 OT_ASSERT(aMax > aMin);
135
136 return (aMin + (GetUint8() % (aMax - aMin)));
137 }
138
GetUint16InRange(uint16_t aMin,uint16_t aMax)139 uint16_t GetUint16InRange(uint16_t aMin, uint16_t aMax)
140 {
141 OT_ASSERT(aMax > aMin);
142 return (aMin + (GetUint16() % (aMax - aMin)));
143 }
144
GetUint32InRange(uint32_t aMin,uint32_t aMax)145 uint32_t GetUint32InRange(uint32_t aMin, uint32_t aMax)
146 {
147 OT_ASSERT(aMax > aMin);
148 return (aMin + (GetUint32() % (aMax - aMin)));
149 }
150
FillBuffer(uint8_t * aBuffer,uint16_t aSize)151 void FillBuffer(uint8_t *aBuffer, uint16_t aSize)
152 {
153 while (aSize-- != 0)
154 {
155 *aBuffer++ = GetUint8();
156 }
157 }
158
AddJitter(uint32_t aValue,uint16_t aJitter)159 uint32_t AddJitter(uint32_t aValue, uint16_t aJitter)
160 {
161 aJitter = (aJitter <= aValue) ? aJitter : static_cast<uint16_t>(aValue);
162
163 return aValue + GetUint32InRange(0, 2 * aJitter + 1) - aJitter;
164 }
165
166 } // namespace NonCrypto
167 } // namespace Random
168 } // namespace ot
169