blob: bac81d8e2c609877d1aac616c9ac69e09d82ea7b [file] [log] [blame]
David Brownfecda2d2017-09-07 10:20:34 -06001/* 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 */
53static void arrInc(uint8_t arr[], uint32_t len)
54{
55 uint32_t i;
56 if (0 != arr)
57 {
58 for (i = len; i > 0U; i--)
59 {
60 if (++arr[i-1] != 0U)
61 {
62 break;
63 }
64 }
65 }
66}
67
68/**
69 * @brief CTR PRNG update
70 * Updates the internal state of supplied the CTR PRNG context
71 * increments it by one
72 * @return none
73 * @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long
74 * @param ctx IN/OUT -- CTR PRNG state
75 * @param providedData IN -- data used when updating the internal state
76 */
77static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData)
78{
79 if (0 != ctx)
80 {
81 /* 10.2.1.2 step 1 */
82 uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
83 uint32_t len = 0U;
84
85 /* 10.2.1.2 step 2 */
86 while (len < sizeof temp)
87 {
88 uint32_t blocklen = sizeof(temp) - len;
89 uint8_t output_block[TC_AES_BLOCK_SIZE];
90
91 /* 10.2.1.2 step 2.1 */
92 arrInc(ctx->V, sizeof ctx->V);
93
94 /* 10.2.1.2 step 2.2 */
95 if (blocklen > TC_AES_BLOCK_SIZE)
96 {
97 blocklen = TC_AES_BLOCK_SIZE;
98 }
99 (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
100
101 /* 10.2.1.2 step 2.3/step 3 */
102 memcpy(&(temp[len]), output_block, blocklen);
103
104 len += blocklen;
105 }
106
107 /* 10.2.1.2 step 4 */
108 if (0 != providedData)
109 {
110 uint32_t i;
111 for (i = 0U; i < sizeof temp; i++)
112 {
113 temp[i] ^= providedData[i];
114 }
115 }
116
117 /* 10.2.1.2 step 5 */
118 (void)tc_aes128_set_encrypt_key(&ctx->key, temp);
119
120 /* 10.2.1.2 step 6 */
121 memcpy(ctx->V, &(temp[TC_AES_KEY_SIZE]), TC_AES_BLOCK_SIZE);
122 }
123}
124
125int32_t tc_ctr_prng_init(TCCtrPrng_t * const ctx,
126 uint8_t const * const entropy,
127 uint32_t entropyLen,
128 uint8_t const * const personalization,
129 uint32_t pLen)
130{
131 int32_t result = TC_CRYPTO_FAIL;
132 uint32_t i;
133 uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
134 uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
135 uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U};
136
137 if (0 != personalization)
138 {
139 /* 10.2.1.3.1 step 1 */
140 uint32_t len = pLen;
141 if (len > sizeof personalization_buf)
142 {
143 len = sizeof personalization_buf;
144 }
145
146 /* 10.2.1.3.1 step 2 */
147 memcpy(personalization_buf, personalization, len);
148 }
149
150 if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material))
151 {
152 /* 10.2.1.3.1 step 3 */
153 memcpy(seed_material, entropy, sizeof seed_material);
154 for (i = 0U; i < sizeof seed_material; i++)
155 {
156 seed_material[i] ^= personalization_buf[i];
157 }
158
159 /* 10.2.1.3.1 step 4 */
160 (void)tc_aes128_set_encrypt_key(&ctx->key, zeroArr);
161
162 /* 10.2.1.3.1 step 5 */
163 memset(ctx->V, 0x00, sizeof ctx->V);
164
165 /* 10.2.1.3.1 step 6 */
166 tc_ctr_prng_update(ctx, seed_material);
167
168 /* 10.2.1.3.1 step 7 */
169 ctx->reseedCount = 1U;
170
171 result = TC_CRYPTO_SUCCESS;
172 }
173 return result;
174}
175
176int32_t tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
177 uint8_t const * const entropy,
178 uint32_t entropyLen,
179 uint8_t const * const additional_input,
180 uint32_t additionallen)
181{
182 uint32_t i;
183 int32_t result = TC_CRYPTO_FAIL;
184 uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
185 uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
186
187 if (0 != additional_input)
188 {
189 /* 10.2.1.4.1 step 1 */
190 uint32_t len = additionallen;
191 if (len > sizeof additional_input_buf)
192 {
193 len = sizeof additional_input_buf;
194 }
195
196 /* 10.2.1.4.1 step 2 */
197 memcpy(additional_input_buf, additional_input, len);
198 }
199
200 uint32_t seedlen = (uint32_t)TC_AES_KEY_SIZE + (uint32_t)TC_AES_BLOCK_SIZE;
201 if ((0 != ctx) && (entropyLen >= seedlen))
202 {
203 /* 10.2.1.4.1 step 3 */
204 memcpy(seed_material, entropy, sizeof seed_material);
205 for (i = 0U; i < sizeof seed_material; i++)
206 {
207 seed_material[i] ^= additional_input_buf[i];
208 }
209
210 /* 10.2.1.4.1 step 4 */
211 tc_ctr_prng_update(ctx, seed_material);
212
213 /* 10.2.1.4.1 step 5 */
214 ctx->reseedCount = 1U;
215
216 result = TC_CRYPTO_SUCCESS;
217 }
218 return result;
219}
220
221int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
222 uint8_t const * const additional_input,
223 uint32_t additionallen,
224 uint8_t * const out,
225 uint32_t outlen)
226{
227 /* 2^48 - see section 10.2.1 */
228 static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL;
229
230 /* 2^19 bits - see section 10.2.1 */
231 static const uint32_t MAX_BYTES_PER_REQ = 65536U;
232
233 int32_t result = TC_CRYPTO_FAIL;
234
235 if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ))
236 {
237 /* 10.2.1.5.1 step 1 */
238 if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED)
239 {
240 result = TC_CTR_PRNG_RESEED_REQ;
241 }
242 else
243 {
244 uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
245 if (0 != additional_input)
246 {
247 /* 10.2.1.5.1 step 2 */
248 uint32_t len = additionallen;
249 if (len > sizeof additional_input_buf)
250 {
251 len = sizeof additional_input_buf;
252 }
253 memcpy(additional_input_buf, additional_input, len);
254 tc_ctr_prng_update(ctx, additional_input_buf);
255 }
256
257 /* 10.2.1.5.1 step 3 - implicit */
258
259 /* 10.2.1.5.1 step 4 */
260 uint32_t len = 0U;
261 while (len < outlen)
262 {
263 uint32_t blocklen = outlen - len;
264 uint8_t output_block[TC_AES_BLOCK_SIZE];
265
266 /* 10.2.1.5.1 step 4.1 */
267 arrInc(ctx->V, sizeof ctx->V);
268
269 /* 10.2.1.5.1 step 4.2 */
270 (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
271
272 /* 10.2.1.5.1 step 4.3/step 5 */
273 if (blocklen > TC_AES_BLOCK_SIZE)
274 {
275 blocklen = TC_AES_BLOCK_SIZE;
276 }
277 memcpy(&(out[len]), output_block, blocklen);
278
279 len += blocklen;
280 }
281
282 /* 10.2.1.5.1 step 6 */
283 tc_ctr_prng_update(ctx, additional_input_buf);
284
285 /* 10.2.1.5.1 step 7 */
286 ctx->reseedCount++;
287
288 /* 10.2.1.5.1 step 8 */
289 result = TC_CRYPTO_SUCCESS;
290 }
291 }
292
293 return result;
294}
295
296void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)
297{
298 if (0 != ctx)
299 {
300 memset(ctx->key.words, 0x00, sizeof ctx->key.words);
301 memset(ctx->V, 0x00, sizeof ctx->V);
302 ctx->reseedCount = 0U;
303 }
304}
305
306
307
308