blob: cac2cc41d60a0ae39fe00d4bec2155bbebbc5530 [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 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -030053static void arrInc(uint8_t arr[], unsigned int len)
David Brownfecda2d2017-09-07 10:20:34 -060054{
Fabio Utzig3efe6b62017-09-22 16:03:24 -030055 unsigned int i;
56 if (0 != arr) {
57 for (i = len; i > 0U; i--) {
58 if (++arr[i-1] != 0U) {
David Brownfecda2d2017-09-07 10:20:34 -060059 break;
60 }
61 }
62 }
63}
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 */
74static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData)
75{
Fabio Utzig3efe6b62017-09-22 16:03:24 -030076 if (0 != ctx) {
David Brownfecda2d2017-09-07 10:20:34 -060077 /* 10.2.1.2 step 1 */
78 uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
Fabio Utzig3efe6b62017-09-22 16:03:24 -030079 unsigned int len = 0U;
David Brownfecda2d2017-09-07 10:20:34 -060080
81 /* 10.2.1.2 step 2 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -030082 while (len < sizeof temp) {
83 unsigned int blocklen = sizeof(temp) - len;
David Brownfecda2d2017-09-07 10:20:34 -060084 uint8_t output_block[TC_AES_BLOCK_SIZE];
85
86 /* 10.2.1.2 step 2.1 */
87 arrInc(ctx->V, sizeof ctx->V);
88
89 /* 10.2.1.2 step 2.2 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -030090 if (blocklen > TC_AES_BLOCK_SIZE) {
David Brownfecda2d2017-09-07 10:20:34 -060091 blocklen = TC_AES_BLOCK_SIZE;
92 }
93 (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
94
95 /* 10.2.1.2 step 2.3/step 3 */
96 memcpy(&(temp[len]), output_block, blocklen);
97
98 len += blocklen;
99 }
100
101 /* 10.2.1.2 step 4 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300102 if (0 != providedData) {
103 unsigned int i;
104 for (i = 0U; i < sizeof temp; i++) {
David Brownfecda2d2017-09-07 10:20:34 -0600105 temp[i] ^= providedData[i];
106 }
107 }
108
109 /* 10.2.1.2 step 5 */
110 (void)tc_aes128_set_encrypt_key(&ctx->key, temp);
111
112 /* 10.2.1.2 step 6 */
113 memcpy(ctx->V, &(temp[TC_AES_KEY_SIZE]), TC_AES_BLOCK_SIZE);
114 }
115}
116
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300117int 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)
David Brownfecda2d2017-09-07 10:20:34 -0600122{
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300123 int result = TC_CRYPTO_FAIL;
124 unsigned int i;
David Brownfecda2d2017-09-07 10:20:34 -0600125 uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
126 uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
127 uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U};
128
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300129 if (0 != personalization) {
David Brownfecda2d2017-09-07 10:20:34 -0600130 /* 10.2.1.3.1 step 1 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300131 unsigned int len = pLen;
132 if (len > sizeof personalization_buf) {
David Brownfecda2d2017-09-07 10:20:34 -0600133 len = sizeof personalization_buf;
134 }
135
136 /* 10.2.1.3.1 step 2 */
137 memcpy(personalization_buf, personalization, len);
138 }
139
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300140 if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) {
David Brownfecda2d2017-09-07 10:20:34 -0600141 /* 10.2.1.3.1 step 3 */
142 memcpy(seed_material, entropy, sizeof seed_material);
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300143 for (i = 0U; i < sizeof seed_material; i++) {
David Brownfecda2d2017-09-07 10:20:34 -0600144 seed_material[i] ^= personalization_buf[i];
145 }
146
147 /* 10.2.1.3.1 step 4 */
148 (void)tc_aes128_set_encrypt_key(&ctx->key, zeroArr);
149
150 /* 10.2.1.3.1 step 5 */
151 memset(ctx->V, 0x00, sizeof ctx->V);
152
153 /* 10.2.1.3.1 step 6 */
154 tc_ctr_prng_update(ctx, seed_material);
155
156 /* 10.2.1.3.1 step 7 */
157 ctx->reseedCount = 1U;
158
159 result = TC_CRYPTO_SUCCESS;
160 }
161 return result;
162}
163
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300164int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
David Brownfecda2d2017-09-07 10:20:34 -0600165 uint8_t const * const entropy,
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300166 unsigned int entropyLen,
David Brownfecda2d2017-09-07 10:20:34 -0600167 uint8_t const * const additional_input,
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300168 unsigned int additionallen)
David Brownfecda2d2017-09-07 10:20:34 -0600169{
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300170 unsigned int i;
171 int result = TC_CRYPTO_FAIL;
David Brownfecda2d2017-09-07 10:20:34 -0600172 uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
173 uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
174
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300175 if (0 != additional_input) {
David Brownfecda2d2017-09-07 10:20:34 -0600176 /* 10.2.1.4.1 step 1 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300177 unsigned int len = additionallen;
178 if (len > sizeof additional_input_buf) {
David Brownfecda2d2017-09-07 10:20:34 -0600179 len = sizeof additional_input_buf;
180 }
181
182 /* 10.2.1.4.1 step 2 */
183 memcpy(additional_input_buf, additional_input, len);
184 }
185
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300186 unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE;
187 if ((0 != ctx) && (entropyLen >= seedlen)) {
David Brownfecda2d2017-09-07 10:20:34 -0600188 /* 10.2.1.4.1 step 3 */
189 memcpy(seed_material, entropy, sizeof seed_material);
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300190 for (i = 0U; i < sizeof seed_material; i++) {
David Brownfecda2d2017-09-07 10:20:34 -0600191 seed_material[i] ^= additional_input_buf[i];
192 }
193
194 /* 10.2.1.4.1 step 4 */
195 tc_ctr_prng_update(ctx, seed_material);
196
197 /* 10.2.1.4.1 step 5 */
198 ctx->reseedCount = 1U;
199
200 result = TC_CRYPTO_SUCCESS;
201 }
202 return result;
203}
204
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300205int tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
David Brownfecda2d2017-09-07 10:20:34 -0600206 uint8_t const * const additional_input,
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300207 unsigned int additionallen,
David Brownfecda2d2017-09-07 10:20:34 -0600208 uint8_t * const out,
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300209 unsigned int outlen)
David Brownfecda2d2017-09-07 10:20:34 -0600210{
211 /* 2^48 - see section 10.2.1 */
212 static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL;
213
214 /* 2^19 bits - see section 10.2.1 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300215 static const unsigned int MAX_BYTES_PER_REQ = 65536U;
David Brownfecda2d2017-09-07 10:20:34 -0600216
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300217 unsigned int result = TC_CRYPTO_FAIL;
David Brownfecda2d2017-09-07 10:20:34 -0600218
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300219 if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) {
David Brownfecda2d2017-09-07 10:20:34 -0600220 /* 10.2.1.5.1 step 1 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300221 if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) {
David Brownfecda2d2017-09-07 10:20:34 -0600222 result = TC_CTR_PRNG_RESEED_REQ;
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300223 } else {
David Brownfecda2d2017-09-07 10:20:34 -0600224 uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300225 if (0 != additional_input) {
David Brownfecda2d2017-09-07 10:20:34 -0600226 /* 10.2.1.5.1 step 2 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300227 unsigned int len = additionallen;
228 if (len > sizeof additional_input_buf) {
David Brownfecda2d2017-09-07 10:20:34 -0600229 len = sizeof additional_input_buf;
230 }
231 memcpy(additional_input_buf, additional_input, len);
232 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 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300238 unsigned int len = 0U;
239 while (len < outlen) {
240 unsigned int blocklen = outlen - len;
David Brownfecda2d2017-09-07 10:20:34 -0600241 uint8_t output_block[TC_AES_BLOCK_SIZE];
242
243 /* 10.2.1.5.1 step 4.1 */
244 arrInc(ctx->V, sizeof ctx->V);
245
246 /* 10.2.1.5.1 step 4.2 */
247 (void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
248
249 /* 10.2.1.5.1 step 4.3/step 5 */
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300250 if (blocklen > TC_AES_BLOCK_SIZE) {
David Brownfecda2d2017-09-07 10:20:34 -0600251 blocklen = TC_AES_BLOCK_SIZE;
252 }
253 memcpy(&(out[len]), output_block, blocklen);
254
255 len += blocklen;
256 }
257
258 /* 10.2.1.5.1 step 6 */
259 tc_ctr_prng_update(ctx, additional_input_buf);
260
261 /* 10.2.1.5.1 step 7 */
262 ctx->reseedCount++;
263
264 /* 10.2.1.5.1 step 8 */
265 result = TC_CRYPTO_SUCCESS;
266 }
267 }
268
269 return result;
270}
271
272void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)
273{
Fabio Utzig3efe6b62017-09-22 16:03:24 -0300274 if (0 != ctx) {
David Brownfecda2d2017-09-07 10:20:34 -0600275 memset(ctx->key.words, 0x00, sizeof ctx->key.words);
276 memset(ctx->V, 0x00, sizeof ctx->V);
277 ctx->reseedCount = 0U;
278 }
279}
280
281
282
283