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     unsigned int i;
56     if (0 != arr) {
57         for (i = len; i > 0U; i--) {
58             if (++arr[i - 1] != 0U) {
59                 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  */
tc_ctr_prng_update(TCCtrPrng_t * const ctx,uint8_t const * const providedData)74 static void tc_ctr_prng_update(TCCtrPrng_t *const ctx, uint8_t const *const providedData)
75 {
76     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         while (len < sizeof temp) {
83             unsigned int blocklen = sizeof(temp) - len;
84             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 */
90             if (blocklen > TC_AES_BLOCK_SIZE) {
91                 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 */
102         if (0 != providedData) {
103             unsigned int i;
104             for (i = 0U; i < sizeof temp; i++) {
105                 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 
tc_ctr_prng_init(TCCtrPrng_t * const ctx,uint8_t const * const entropy,unsigned int entropyLen,uint8_t const * const personalization,unsigned int pLen)117 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     int result = TC_CRYPTO_FAIL;
124     unsigned int i;
125     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 
129     if (0 != personalization) {
130         /* 10.2.1.3.1 step 1 */
131         unsigned int len = pLen;
132         if (len > sizeof personalization_buf) {
133             len = sizeof personalization_buf;
134         }
135 
136         /* 10.2.1.3.1 step 2 */
137         memcpy(personalization_buf, personalization, len);
138     }
139 
140     if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) {
141         /* 10.2.1.3.1 step 3 */
142         memcpy(seed_material, entropy, sizeof seed_material);
143         for (i = 0U; i < sizeof seed_material; i++) {
144             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 
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)164 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     unsigned int i;
171     int result = TC_CRYPTO_FAIL;
172     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 
175     if (0 != additional_input) {
176         /* 10.2.1.4.1 step 1 */
177         unsigned int len = additionallen;
178         if (len > sizeof additional_input_buf) {
179             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 
186     unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE;
187     if ((0 != ctx) && (entropyLen >= seedlen)) {
188         /* 10.2.1.4.1 step 3 */
189         memcpy(seed_material, entropy, sizeof seed_material);
190         for (i = 0U; i < sizeof seed_material; i++) {
191             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 
tc_ctr_prng_generate(TCCtrPrng_t * const ctx,uint8_t const * const additional_input,unsigned int additionallen,uint8_t * const out,unsigned int outlen)205 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     static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL;
213 
214     /* 2^19 bits - see section 10.2.1 */
215     static const unsigned int MAX_BYTES_PER_REQ = 65536U;
216 
217     unsigned int result = TC_CRYPTO_FAIL;
218 
219     if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) {
220         /* 10.2.1.5.1 step 1 */
221         if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) {
222             result = TC_CTR_PRNG_RESEED_REQ;
223         } else {
224             uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
225             if (0 != additional_input) {
226                 /* 10.2.1.5.1 step 2  */
227                 unsigned int len = additionallen;
228                 if (len > sizeof additional_input_buf) {
229                     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 */
238             unsigned int len = 0U;
239             while (len < outlen) {
240                 unsigned int blocklen = outlen - len;
241                 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 */
250                 if (blocklen > TC_AES_BLOCK_SIZE) {
251                     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 
tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)272 void tc_ctr_prng_uninstantiate(TCCtrPrng_t *const ctx)
273 {
274     if (0 != ctx) {
275         memset(ctx->key.words, 0x00, sizeof ctx->key.words);
276         memset(ctx->V,         0x00, sizeof ctx->V);
277         ctx->reseedCount = 0U;
278     }
279 }
280