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