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