xref: /nrf52832-nimble/packages/NimBLE-latest/ext/tinycrypt/src/ctr_prng.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /* ctr_prng.c - TinyCrypt implementation of CTR-PRNG */
2*042d53a7SEvalZero 
3*042d53a7SEvalZero /*
4*042d53a7SEvalZero  * Copyright (c) 2016, Chris Morrison
5*042d53a7SEvalZero  * All rights reserved.
6*042d53a7SEvalZero  *
7*042d53a7SEvalZero  * Redistribution and use in source and binary forms, with or without
8*042d53a7SEvalZero  * modification, are permitted provided that the following conditions are met:
9*042d53a7SEvalZero  *
10*042d53a7SEvalZero  * * Redistributions of source code must retain the above copyright notice, this
11*042d53a7SEvalZero  *   list of conditions and the following disclaimer.
12*042d53a7SEvalZero  *
13*042d53a7SEvalZero  * * Redistributions in binary form must reproduce the above copyright notice,
14*042d53a7SEvalZero  *   this list of conditions and the following disclaimer in the documentation
15*042d53a7SEvalZero  *   and/or other materials provided with the distribution.
16*042d53a7SEvalZero  *
17*042d53a7SEvalZero  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*042d53a7SEvalZero  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*042d53a7SEvalZero  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*042d53a7SEvalZero  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*042d53a7SEvalZero  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*042d53a7SEvalZero  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*042d53a7SEvalZero  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*042d53a7SEvalZero  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*042d53a7SEvalZero  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*042d53a7SEvalZero  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*042d53a7SEvalZero  * POSSIBILITY OF SUCH DAMAGE.
28*042d53a7SEvalZero  */
29*042d53a7SEvalZero 
30*042d53a7SEvalZero #include <tinycrypt/ctr_prng.h>
31*042d53a7SEvalZero #include <tinycrypt/utils.h>
32*042d53a7SEvalZero #include <tinycrypt/constants.h>
33*042d53a7SEvalZero #include <string.h>
34*042d53a7SEvalZero 
35*042d53a7SEvalZero /*
36*042d53a7SEvalZero  * This PRNG is based on the CTR_DRBG described in Recommendation for Random
37*042d53a7SEvalZero  * Number Generation Using Deterministic Random Bit Generators,
38*042d53a7SEvalZero  * NIST SP 800-90A Rev. 1.
39*042d53a7SEvalZero  *
40*042d53a7SEvalZero  * Annotations to particular steps (e.g. 10.2.1.2 Step 1) refer to the steps
41*042d53a7SEvalZero  * described in that document.
42*042d53a7SEvalZero  *
43*042d53a7SEvalZero  */
44*042d53a7SEvalZero 
45*042d53a7SEvalZero /**
46*042d53a7SEvalZero  *  @brief Array incrementer
47*042d53a7SEvalZero  *  Treats the supplied array as one contiguous number (MSB in arr[0]), and
48*042d53a7SEvalZero  *  increments it by one
49*042d53a7SEvalZero  *  @return none
50*042d53a7SEvalZero  *  @param arr IN/OUT -- array to be incremented
51*042d53a7SEvalZero  *  @param len IN -- size of arr in bytes
52*042d53a7SEvalZero  */
arrInc(uint8_t arr[],unsigned int len)53*042d53a7SEvalZero static void arrInc(uint8_t arr[], unsigned int len)
54*042d53a7SEvalZero {
55*042d53a7SEvalZero 	unsigned int i;
56*042d53a7SEvalZero 	if (0 != arr) {
57*042d53a7SEvalZero 		for (i = len; i > 0U; i--) {
58*042d53a7SEvalZero 			if (++arr[i-1] != 0U) {
59*042d53a7SEvalZero 				break;
60*042d53a7SEvalZero 			}
61*042d53a7SEvalZero 		}
62*042d53a7SEvalZero 	}
63*042d53a7SEvalZero }
64*042d53a7SEvalZero 
65*042d53a7SEvalZero /**
66*042d53a7SEvalZero  *  @brief CTR PRNG update
67*042d53a7SEvalZero  *  Updates the internal state of supplied the CTR PRNG context
68*042d53a7SEvalZero  *  increments it by one
69*042d53a7SEvalZero  *  @return none
70*042d53a7SEvalZero  *  @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long
71*042d53a7SEvalZero  *  @param ctx IN/OUT -- CTR PRNG state
72*042d53a7SEvalZero  *  @param providedData IN -- data used when updating the internal state
73*042d53a7SEvalZero  */
tc_ctr_prng_update(TCCtrPrng_t * const ctx,uint8_t const * const providedData)74*042d53a7SEvalZero static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData)
75*042d53a7SEvalZero {
76*042d53a7SEvalZero 	if (0 != ctx) {
77*042d53a7SEvalZero 		/* 10.2.1.2 step 1 */
78*042d53a7SEvalZero 		uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
79*042d53a7SEvalZero 		unsigned int len = 0U;
80*042d53a7SEvalZero 
81*042d53a7SEvalZero 		/* 10.2.1.2 step 2 */
82*042d53a7SEvalZero 		while (len < sizeof temp) {
83*042d53a7SEvalZero 			unsigned int blocklen = sizeof(temp) - len;
84*042d53a7SEvalZero 			uint8_t output_block[TC_AES_BLOCK_SIZE];
85*042d53a7SEvalZero 
86*042d53a7SEvalZero 			/* 10.2.1.2 step 2.1 */
87*042d53a7SEvalZero 			arrInc(ctx->V, sizeof ctx->V);
88*042d53a7SEvalZero 
89*042d53a7SEvalZero 			/* 10.2.1.2 step 2.2 */
90*042d53a7SEvalZero 			if (blocklen > TC_AES_BLOCK_SIZE) {
91*042d53a7SEvalZero 				blocklen = TC_AES_BLOCK_SIZE;
92*042d53a7SEvalZero 			}
93*042d53a7SEvalZero 			(void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
94*042d53a7SEvalZero 
95*042d53a7SEvalZero 			/* 10.2.1.2 step 2.3/step 3 */
96*042d53a7SEvalZero 			memcpy(&(temp[len]), output_block, blocklen);
97*042d53a7SEvalZero 
98*042d53a7SEvalZero 			len += blocklen;
99*042d53a7SEvalZero 		}
100*042d53a7SEvalZero 
101*042d53a7SEvalZero 		/* 10.2.1.2 step 4 */
102*042d53a7SEvalZero 		if (0 != providedData) {
103*042d53a7SEvalZero 			unsigned int i;
104*042d53a7SEvalZero 			for (i = 0U; i < sizeof temp; i++) {
105*042d53a7SEvalZero 				temp[i] ^= providedData[i];
106*042d53a7SEvalZero 			}
107*042d53a7SEvalZero 		}
108*042d53a7SEvalZero 
109*042d53a7SEvalZero 		/* 10.2.1.2 step 5 */
110*042d53a7SEvalZero 		(void)tc_aes128_set_encrypt_key(&ctx->key, temp);
111*042d53a7SEvalZero 
112*042d53a7SEvalZero 		/* 10.2.1.2 step 6 */
113*042d53a7SEvalZero 		memcpy(ctx->V, &(temp[TC_AES_KEY_SIZE]), TC_AES_BLOCK_SIZE);
114*042d53a7SEvalZero 	}
115*042d53a7SEvalZero }
116*042d53a7SEvalZero 
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*042d53a7SEvalZero int tc_ctr_prng_init(TCCtrPrng_t * const ctx,
118*042d53a7SEvalZero 		     uint8_t const * const entropy,
119*042d53a7SEvalZero 		     unsigned int entropyLen,
120*042d53a7SEvalZero 		     uint8_t const * const personalization,
121*042d53a7SEvalZero 		     unsigned int pLen)
122*042d53a7SEvalZero {
123*042d53a7SEvalZero 	int result = TC_CRYPTO_FAIL;
124*042d53a7SEvalZero 	unsigned int i;
125*042d53a7SEvalZero 	uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
126*042d53a7SEvalZero 	uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
127*042d53a7SEvalZero 	uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U};
128*042d53a7SEvalZero 
129*042d53a7SEvalZero 	if (0 != personalization) {
130*042d53a7SEvalZero 		/* 10.2.1.3.1 step 1 */
131*042d53a7SEvalZero 		unsigned int len = pLen;
132*042d53a7SEvalZero 		if (len > sizeof personalization_buf) {
133*042d53a7SEvalZero 			len = sizeof personalization_buf;
134*042d53a7SEvalZero 		}
135*042d53a7SEvalZero 
136*042d53a7SEvalZero 		/* 10.2.1.3.1 step 2 */
137*042d53a7SEvalZero 		memcpy(personalization_buf, personalization, len);
138*042d53a7SEvalZero 	}
139*042d53a7SEvalZero 
140*042d53a7SEvalZero 	if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) {
141*042d53a7SEvalZero 		/* 10.2.1.3.1 step 3 */
142*042d53a7SEvalZero 		memcpy(seed_material, entropy, sizeof seed_material);
143*042d53a7SEvalZero 		for (i = 0U; i < sizeof seed_material; i++) {
144*042d53a7SEvalZero 			seed_material[i] ^= personalization_buf[i];
145*042d53a7SEvalZero 		}
146*042d53a7SEvalZero 
147*042d53a7SEvalZero 		/* 10.2.1.3.1 step 4 */
148*042d53a7SEvalZero 		(void)tc_aes128_set_encrypt_key(&ctx->key, zeroArr);
149*042d53a7SEvalZero 
150*042d53a7SEvalZero 		/* 10.2.1.3.1 step 5 */
151*042d53a7SEvalZero 		memset(ctx->V,   0x00, sizeof ctx->V);
152*042d53a7SEvalZero 
153*042d53a7SEvalZero 		/* 10.2.1.3.1 step 6 */
154*042d53a7SEvalZero 		tc_ctr_prng_update(ctx, seed_material);
155*042d53a7SEvalZero 
156*042d53a7SEvalZero 		/* 10.2.1.3.1 step 7 */
157*042d53a7SEvalZero 		ctx->reseedCount = 1U;
158*042d53a7SEvalZero 
159*042d53a7SEvalZero 		result = TC_CRYPTO_SUCCESS;
160*042d53a7SEvalZero 	}
161*042d53a7SEvalZero 	return result;
162*042d53a7SEvalZero }
163*042d53a7SEvalZero 
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*042d53a7SEvalZero int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
165*042d53a7SEvalZero 			uint8_t const * const entropy,
166*042d53a7SEvalZero 			unsigned int entropyLen,
167*042d53a7SEvalZero 			uint8_t const * const additional_input,
168*042d53a7SEvalZero 			unsigned int additionallen)
169*042d53a7SEvalZero {
170*042d53a7SEvalZero 	unsigned int i;
171*042d53a7SEvalZero 	int result = TC_CRYPTO_FAIL;
172*042d53a7SEvalZero 	uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
173*042d53a7SEvalZero 	uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
174*042d53a7SEvalZero 
175*042d53a7SEvalZero 	if (0 != additional_input) {
176*042d53a7SEvalZero 		/* 10.2.1.4.1 step 1 */
177*042d53a7SEvalZero 		unsigned int len = additionallen;
178*042d53a7SEvalZero 		if (len > sizeof additional_input_buf) {
179*042d53a7SEvalZero 			len = sizeof additional_input_buf;
180*042d53a7SEvalZero 		}
181*042d53a7SEvalZero 
182*042d53a7SEvalZero 		/* 10.2.1.4.1 step 2 */
183*042d53a7SEvalZero 		memcpy(additional_input_buf, additional_input, len);
184*042d53a7SEvalZero 	}
185*042d53a7SEvalZero 
186*042d53a7SEvalZero 	unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE;
187*042d53a7SEvalZero 	if ((0 != ctx) && (entropyLen >= seedlen)) {
188*042d53a7SEvalZero 		/* 10.2.1.4.1 step 3 */
189*042d53a7SEvalZero 		memcpy(seed_material, entropy, sizeof seed_material);
190*042d53a7SEvalZero 		for (i = 0U; i < sizeof seed_material; i++) {
191*042d53a7SEvalZero 			seed_material[i] ^= additional_input_buf[i];
192*042d53a7SEvalZero 		}
193*042d53a7SEvalZero 
194*042d53a7SEvalZero 		/* 10.2.1.4.1 step 4 */
195*042d53a7SEvalZero 		tc_ctr_prng_update(ctx, seed_material);
196*042d53a7SEvalZero 
197*042d53a7SEvalZero 		/* 10.2.1.4.1 step 5 */
198*042d53a7SEvalZero 		ctx->reseedCount = 1U;
199*042d53a7SEvalZero 
200*042d53a7SEvalZero 		result = TC_CRYPTO_SUCCESS;
201*042d53a7SEvalZero 	}
202*042d53a7SEvalZero 	return result;
203*042d53a7SEvalZero }
204*042d53a7SEvalZero 
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*042d53a7SEvalZero int tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
206*042d53a7SEvalZero 			uint8_t const * const additional_input,
207*042d53a7SEvalZero 			unsigned int additionallen,
208*042d53a7SEvalZero 			uint8_t * const out,
209*042d53a7SEvalZero 			unsigned int outlen)
210*042d53a7SEvalZero {
211*042d53a7SEvalZero 	/* 2^48 - see section 10.2.1 */
212*042d53a7SEvalZero 	static const uint64_t MAX_REQS_BEFORE_RESEED = 0x1000000000000ULL;
213*042d53a7SEvalZero 
214*042d53a7SEvalZero 	/* 2^19 bits - see section 10.2.1 */
215*042d53a7SEvalZero 	static const unsigned int MAX_BYTES_PER_REQ = 65536U;
216*042d53a7SEvalZero 
217*042d53a7SEvalZero 	unsigned int result = TC_CRYPTO_FAIL;
218*042d53a7SEvalZero 
219*042d53a7SEvalZero 	if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) {
220*042d53a7SEvalZero 		/* 10.2.1.5.1 step 1 */
221*042d53a7SEvalZero 		if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) {
222*042d53a7SEvalZero 			result = TC_CTR_PRNG_RESEED_REQ;
223*042d53a7SEvalZero 		} else {
224*042d53a7SEvalZero 			uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
225*042d53a7SEvalZero 			if (0 != additional_input) {
226*042d53a7SEvalZero 				/* 10.2.1.5.1 step 2  */
227*042d53a7SEvalZero 				unsigned int len = additionallen;
228*042d53a7SEvalZero 				if (len > sizeof additional_input_buf) {
229*042d53a7SEvalZero 					len = sizeof additional_input_buf;
230*042d53a7SEvalZero 				}
231*042d53a7SEvalZero 				memcpy(additional_input_buf, additional_input, len);
232*042d53a7SEvalZero 				tc_ctr_prng_update(ctx, additional_input_buf);
233*042d53a7SEvalZero 			}
234*042d53a7SEvalZero 
235*042d53a7SEvalZero 			/* 10.2.1.5.1 step 3 - implicit */
236*042d53a7SEvalZero 
237*042d53a7SEvalZero 			/* 10.2.1.5.1 step 4 */
238*042d53a7SEvalZero 			unsigned int len = 0U;
239*042d53a7SEvalZero 			while (len < outlen) {
240*042d53a7SEvalZero 				unsigned int blocklen = outlen - len;
241*042d53a7SEvalZero 				uint8_t output_block[TC_AES_BLOCK_SIZE];
242*042d53a7SEvalZero 
243*042d53a7SEvalZero 				/* 10.2.1.5.1 step 4.1 */
244*042d53a7SEvalZero 				arrInc(ctx->V, sizeof ctx->V);
245*042d53a7SEvalZero 
246*042d53a7SEvalZero 				/* 10.2.1.5.1 step 4.2 */
247*042d53a7SEvalZero 				(void)tc_aes_encrypt(output_block, ctx->V, &ctx->key);
248*042d53a7SEvalZero 
249*042d53a7SEvalZero 				/* 10.2.1.5.1 step 4.3/step 5 */
250*042d53a7SEvalZero 				if (blocklen > TC_AES_BLOCK_SIZE) {
251*042d53a7SEvalZero 					blocklen = TC_AES_BLOCK_SIZE;
252*042d53a7SEvalZero 				}
253*042d53a7SEvalZero 				memcpy(&(out[len]), output_block, blocklen);
254*042d53a7SEvalZero 
255*042d53a7SEvalZero 				len += blocklen;
256*042d53a7SEvalZero 			}
257*042d53a7SEvalZero 
258*042d53a7SEvalZero 			/* 10.2.1.5.1 step 6 */
259*042d53a7SEvalZero 			tc_ctr_prng_update(ctx, additional_input_buf);
260*042d53a7SEvalZero 
261*042d53a7SEvalZero 			/* 10.2.1.5.1 step 7 */
262*042d53a7SEvalZero 			ctx->reseedCount++;
263*042d53a7SEvalZero 
264*042d53a7SEvalZero 			/* 10.2.1.5.1 step 8 */
265*042d53a7SEvalZero 			result = TC_CRYPTO_SUCCESS;
266*042d53a7SEvalZero 		}
267*042d53a7SEvalZero 	}
268*042d53a7SEvalZero 
269*042d53a7SEvalZero 	return result;
270*042d53a7SEvalZero }
271*042d53a7SEvalZero 
tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)272*042d53a7SEvalZero void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)
273*042d53a7SEvalZero {
274*042d53a7SEvalZero 	if (0 != ctx) {
275*042d53a7SEvalZero 		memset(ctx->key.words, 0x00, sizeof ctx->key.words);
276*042d53a7SEvalZero 		memset(ctx->V,         0x00, sizeof ctx->V);
277*042d53a7SEvalZero 		ctx->reseedCount = 0U;
278*042d53a7SEvalZero 	}
279*042d53a7SEvalZero }
280*042d53a7SEvalZero 
281*042d53a7SEvalZero 
282*042d53a7SEvalZero 
283*042d53a7SEvalZero 
284