Branch data Line data Source code
1 : : /* ctr_prng.c - TinyCrypt implementation of CTR-PRNG */
2 : :
3 : : /*
4 : : * Copyright (c) 2016, Chris Morrison
5 : : * All rights reserved.
6 : : *
7 : : * Redistribution and use in source and binary forms, with or without
8 : : * modification, are permitted provided that the following conditions are met:
9 : : *
10 : : * * Redistributions of source code must retain the above copyright notice, this
11 : : * list of conditions and the following disclaimer.
12 : : *
13 : : * * Redistributions in binary form must reproduce the above copyright notice,
14 : : * this list of conditions and the following disclaimer in the documentation
15 : : * and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 : : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 : : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 : : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 : : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 : : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 : : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 : : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 : : * POSSIBILITY OF SUCH DAMAGE.
28 : : */
29 : :
30 : : #include <tinycrypt/ctr_prng.h>
31 : : #include <tinycrypt/utils.h>
32 : : #include <tinycrypt/constants.h>
33 : : #include <string.h>
34 : :
35 : : /*
36 : : * This PRNG is based on the CTR_DRBG described in Recommendation for Random
37 : : * Number Generation Using Deterministic Random Bit Generators,
38 : : * NIST SP 800-90A Rev. 1.
39 : : *
40 : : * Annotations to particular steps (e.g. 10.2.1.2 Step 1) refer to the steps
41 : : * described in that document.
42 : : *
43 : : */
44 : :
45 : : /**
46 : : * @brief Array incrementer
47 : : * Treats the supplied array as one contiguous number (MSB in arr[0]), and
48 : : * increments it by one
49 : : * @return none
50 : : * @param arr IN/OUT -- array to be incremented
51 : : * @param len IN -- size of arr in bytes
52 : : */
53 : 0 : static void arrInc(uint8_t arr[], unsigned int len)
54 : : {
55 : 0 : unsigned int i;
56 [ # # ]: 0 : if (0 != arr) {
57 [ # # ]: 0 : for (i = len; i > 0U; i--) {
58 [ # # ]: 0 : if (++arr[i-1] != 0U) {
59 : : break;
60 : : }
61 : : }
62 : : }
63 : 0 : }
64 : :
65 : : /**
66 : : * @brief CTR PRNG update
67 : : * Updates the internal state of supplied the CTR PRNG context
68 : : * increments it by one
69 : : * @return none
70 : : * @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long
71 : : * @param ctx IN/OUT -- CTR PRNG state
72 : : * @param providedData IN -- data used when updating the internal state
73 : : */
74 : 0 : static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData)
75 : : {
76 [ # # ]: 0 : if (0 != ctx) {
77 : : /* 10.2.1.2 step 1 */
78 : : uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
79 : : unsigned int len = 0U;
80 : :
81 : : /* 10.2.1.2 step 2 */
82 [ # # ]: 0 : while (len < sizeof temp) {
83 : 0 : unsigned int blocklen = sizeof(temp) - len;
84 : 0 : uint8_t output_block[TC_AES_BLOCK_SIZE];
85 : :
86 : : /* 10.2.1.2 step 2.1 */
87 : 0 : arrInc(ctx->V, sizeof ctx->V);
88 : :
89 : : /* 10.2.1.2 step 2.2 */
90 : 0 : if (blocklen > TC_AES_BLOCK_SIZE) {
91 : : blocklen = TC_AES_BLOCK_SIZE;
92 : : }
93 : 0 : (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
94 : :
95 : : /* 10.2.1.2 step 2.3/step 3 */
96 : 0 : memcpy(&(temp[len]), output_block, blocklen);
97 : :
98 : 0 : len += blocklen;
99 : : }
100 : :
101 : : /* 10.2.1.2 step 4 */
102 [ # # ]: 0 : if (0 != providedData) {
103 : : unsigned int i;
104 [ # # ]: 0 : for (i = 0U; i < sizeof temp; i++) {
105 : 0 : temp[i] ^= providedData[i];
106 : : }
107 : : }
108 : :
109 : : /* 10.2.1.2 step 5 */
110 : 0 : (void)tc_aes128_set_encrypt_key(&ctx->key, temp);
111 : :
112 : : /* 10.2.1.2 step 6 */
113 : 0 : memcpy(ctx->V, &(temp[TC_AES_KEY_SIZE]), TC_AES_BLOCK_SIZE);
114 : : }
115 : 0 : }
116 : :
117 : 0 : int tc_ctr_prng_init(TCCtrPrng_t * const ctx,
118 : : uint8_t const * const entropy,
119 : : unsigned int entropyLen,
120 : : uint8_t const * const personalization,
121 : : unsigned int pLen)
122 : : {
123 : 0 : int result = TC_CRYPTO_FAIL;
124 : 0 : unsigned int i;
125 : 0 : uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
126 : 0 : uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
127 : 0 : uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U};
128 : :
129 [ # # ]: 0 : if (0 != personalization) {
130 : : /* 10.2.1.3.1 step 1 */
131 : 0 : unsigned int len = pLen;
132 : 0 : if (len > sizeof personalization_buf) {
133 : : len = sizeof personalization_buf;
134 : : }
135 : :
136 : : /* 10.2.1.3.1 step 2 */
137 : 0 : memcpy(personalization_buf, personalization, len);
138 : : }
139 : :
140 [ # # # # ]: 0 : if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) {
141 : : /* 10.2.1.3.1 step 3 */
142 : 0 : memcpy(seed_material, entropy, sizeof seed_material);
143 [ # # ]: 0 : for (i = 0U; i < sizeof seed_material; i++) {
144 : 0 : seed_material[i] ^= personalization_buf[i];
145 : : }
146 : :
147 : : /* 10.2.1.3.1 step 4 */
148 : 0 : (void)tc_aes128_set_encrypt_key(&ctx->key, zeroArr);
149 : :
150 : : /* 10.2.1.3.1 step 5 */
151 : 0 : memset(ctx->V, 0x00, sizeof ctx->V);
152 : :
153 : : /* 10.2.1.3.1 step 6 */
154 : 0 : tc_ctr_prng_update(ctx, seed_material);
155 : :
156 : : /* 10.2.1.3.1 step 7 */
157 : 0 : ctx->reseedCount = 1U;
158 : :
159 : 0 : result = TC_CRYPTO_SUCCESS;
160 : : }
161 : 0 : return result;
162 : : }
163 : :
164 : 0 : int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
165 : : uint8_t const * const entropy,
166 : : unsigned int entropyLen,
167 : : uint8_t const * const additional_input,
168 : : unsigned int additionallen)
169 : : {
170 : 0 : unsigned int i;
171 : 0 : int result = TC_CRYPTO_FAIL;
172 : 0 : uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
173 : 0 : uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
174 : :
175 [ # # ]: 0 : if (0 != additional_input) {
176 : : /* 10.2.1.4.1 step 1 */
177 : 0 : unsigned int len = additionallen;
178 : 0 : if (len > sizeof additional_input_buf) {
179 : : len = sizeof additional_input_buf;
180 : : }
181 : :
182 : : /* 10.2.1.4.1 step 2 */
183 : 0 : memcpy(additional_input_buf, additional_input, len);
184 : : }
185 : :
186 : 0 : unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE;
187 [ # # ]: 0 : if ((0 != ctx) && (entropyLen >= seedlen)) {
188 : : /* 10.2.1.4.1 step 3 */
189 : 0 : memcpy(seed_material, entropy, sizeof seed_material);
190 [ # # ]: 0 : for (i = 0U; i < sizeof seed_material; i++) {
191 : 0 : seed_material[i] ^= additional_input_buf[i];
192 : : }
193 : :
194 : : /* 10.2.1.4.1 step 4 */
195 : 0 : tc_ctr_prng_update(ctx, seed_material);
196 : :
197 : : /* 10.2.1.4.1 step 5 */
198 : 0 : ctx->reseedCount = 1U;
199 : :
200 : 0 : result = TC_CRYPTO_SUCCESS;
201 : : }
202 : 0 : return result;
203 : : }
204 : :
205 : 0 : int tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
206 : : uint8_t const * const additional_input,
207 : : unsigned int additionallen,
208 : : uint8_t * const out,
209 : : unsigned int outlen)
210 : : {
211 : : /* 2^48 - see section 10.2.1 */
212 : 0 : static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL;
213 : :
214 : : /* 2^19 bits - see section 10.2.1 */
215 : 0 : static const unsigned int MAX_BYTES_PER_REQ = 65536U;
216 : :
217 : 0 : unsigned int result = TC_CRYPTO_FAIL;
218 : :
219 [ # # # # ]: 0 : if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) {
220 : : /* 10.2.1.5.1 step 1 */
221 [ # # ]: 0 : if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) {
222 : : result = TC_CTR_PRNG_RESEED_REQ;
223 : : } else {
224 : 0 : uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
225 [ # # ]: 0 : if (0 != additional_input) {
226 : : /* 10.2.1.5.1 step 2 */
227 : 0 : unsigned int len = additionallen;
228 : 0 : if (len > sizeof additional_input_buf) {
229 : : len = sizeof additional_input_buf;
230 : : }
231 : 0 : memcpy(additional_input_buf, additional_input, len);
232 : 0 : tc_ctr_prng_update(ctx, additional_input_buf);
233 : : }
234 : :
235 : : /* 10.2.1.5.1 step 3 - implicit */
236 : :
237 : : /* 10.2.1.5.1 step 4 */
238 : : unsigned int len = 0U;
239 [ # # ]: 0 : while (len < outlen) {
240 : 0 : unsigned int blocklen = outlen - len;
241 : 0 : uint8_t output_block[TC_AES_BLOCK_SIZE];
242 : :
243 : : /* 10.2.1.5.1 step 4.1 */
244 : 0 : arrInc(ctx->V, sizeof ctx->V);
245 : :
246 : : /* 10.2.1.5.1 step 4.2 */
247 : 0 : (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
248 : :
249 : : /* 10.2.1.5.1 step 4.3/step 5 */
250 : 0 : if (blocklen > TC_AES_BLOCK_SIZE) {
251 : : blocklen = TC_AES_BLOCK_SIZE;
252 : : }
253 : 0 : memcpy(&(out[len]), output_block, blocklen);
254 : :
255 : 0 : len += blocklen;
256 : : }
257 : :
258 : : /* 10.2.1.5.1 step 6 */
259 : 0 : tc_ctr_prng_update(ctx, additional_input_buf);
260 : :
261 : : /* 10.2.1.5.1 step 7 */
262 : 0 : ctx->reseedCount++;
263 : :
264 : : /* 10.2.1.5.1 step 8 */
265 : 0 : result = TC_CRYPTO_SUCCESS;
266 : : }
267 : : }
268 : :
269 : 0 : return result;
270 : : }
271 : :
272 : 0 : void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)
273 : : {
274 [ # # ]: 0 : if (0 != ctx) {
275 : 0 : memset(ctx->key.words, 0x00, sizeof ctx->key.words);
276 : 0 : memset(ctx->V, 0x00, sizeof ctx->V);
277 : 0 : ctx->reseedCount = 0U;
278 : : }
279 : 0 : }
280 : :
281 : :
282 : :
283 : :
|