• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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