Skip to content
This repository was archived by the owner on Mar 5, 2024. It is now read-only.

Commit 853e01c

Browse files
Adding support for additional input when reseeding/generating ctr prngs. Also added documentation
1 parent 4860c47 commit 853e01c

File tree

3 files changed

+275
-35
lines changed

3 files changed

+275
-35
lines changed

lib/include/tinycrypt/ctr_prng.h

Lines changed: 129 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,61 @@
11
/* ctr_prng.h - TinyCrypt interface to an CTR-PRNG implementation */
22

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+
/**
31+
* @file
32+
* @brief Interface to an CTR-PRNG implementation.
33+
*
34+
* Overview: A pseudo-random number generator (PRNG) generates a sequence
35+
* of numbers that have a distribution close to the one expected
36+
* for a sequence of truly random numbers. The NIST Special
37+
* Publication 800-90A specifies several mechanisms to generate
38+
* sequences of pseudo random numbers, including the CTR-PRNG one
39+
* which is based on AES. TinyCrypt implements CTR-PRNG with
40+
* AES-128.
41+
*
42+
* Security: A cryptographically secure PRNG depends on the existence of an
43+
* entropy source to provide a truly random seed as well as the
44+
* security of the primitives used as the building blocks (AES-128
45+
* in this instance).
46+
*
47+
* Requires: - AES-128
48+
*
49+
* Usage: 1) call tc_ctr_prng_init to seed the prng context
50+
*
51+
* 2) call tc_ctr_prng_reseed to mix in additional entropy into
52+
* the prng context
53+
*
54+
* 3) call tc_ctr_prng_generate to output the pseudo-random data
55+
*
56+
* 4) call tc_ctr_prng_uninstantiate to zero out the prng context
57+
*/
58+
359
#ifndef __TC_CTR_PRNG_H__
460
#define __TC_CTR_PRNG_H__
561

@@ -17,27 +73,91 @@ typedef struct
1773
/* updated whenever the PRNG is reseeded */
1874
struct tc_aes_key_sched_struct key;
1975

20-
/* number of requests since initialisation/reseeding */
76+
/* number of requests since initialization/reseeding */
2177
uint64_t reseedCount;
2278
} TCCtrPrng_t;
2379

2480

25-
//todo comment
81+
/**
82+
* @brief CTR-PRNG initialization procedure
83+
* Initializes prng context with entropy and personalization string (if any)
84+
* @return returns TC_SUCCESS (1)
85+
* returns TC_FAIL (0) if:
86+
* ctx == NULL,
87+
* entropy == NULL,
88+
* entropyLen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE)
89+
* @note Only the first (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes of
90+
* both the entropy and personalization inputs are used -
91+
* supplying additional bytes has no effect.
92+
* @param ctx IN/OUT -- the PRNG context to initialize
93+
* @param entropy IN -- entropy used to seed the PRNG
94+
* @param entropyLen IN -- entropy length in bytes
95+
* @param personalization IN -- personalization string used to seed the PRNG
96+
* (may be null)
97+
* @param plen IN -- personalization length in bytes
98+
*
99+
*/
26100
int32_t tc_ctr_prng_init(TCCtrPrng_t * const ctx,
27-
uint8_t const entropy[],
101+
uint8_t const * const entropy,
28102
uint32_t entropyLen,
29-
uint8_t const personalization[],
103+
uint8_t const * const personalization,
30104
uint32_t pLen);
31105

32-
//todo comment
106+
/**
107+
* @brief CTR-PRNG reseed procedure
108+
* Mixes entropy and additional_input into the prng context
109+
* @return returns TC_SUCCESS (1)
110+
* returns TC_FAIL (0) if:
111+
* ctx == NULL,
112+
* entropy == NULL,
113+
* entropylen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE)
114+
* @note It is better to reseed an existing prng context rather than
115+
* re-initialise, so that any existing entropy in the context is
116+
* presereved. This offers some protection against undetected failures
117+
* of the entropy source.
118+
* @note Assumes tc_ctr_prng_init has been called for ctx
119+
* @param ctx IN/OUT -- the PRNG state
120+
* @param entropy IN -- entropy to mix into the prng
121+
* @param entropylen IN -- length of entropy in bytes
122+
* @param additional_input IN -- additional input to the prng (may be null)
123+
* @param additionallen IN -- additional input length in bytes
124+
*/
33125
int32_t tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
34-
uint8_t const entropy[],
35-
uint32_t entropyLen);
126+
uint8_t const * const entropy,
127+
uint32_t entropyLen,
128+
uint8_t const * const additional_input,
129+
uint32_t additionallen);
36130

37-
int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
38-
uint8_t out[],
131+
/**
132+
* @brief CTR-PRNG generate procedure
133+
* Generates outlen pseudo-random bytes into out buffer, updates prng
134+
* @return returns TC_SUCCESS (1)
135+
* returns TC_RESEED_REQ (-1) if a reseed is needed
136+
* returns TC_FAIL (0) if:
137+
* ctx == NULL,
138+
* out == NULL,
139+
* outlen >= 2^16
140+
* @note Assumes tc_ctr_prng_init has been called for ctx
141+
* @param ctx IN/OUT -- the PRNG context
142+
* @param additional_input IN -- additional input to the prng (may be null)
143+
* @param additionallen IN -- additional input length in bytes
144+
* @param out IN/OUT -- buffer to receive output
145+
* @param outlen IN -- size of out buffer in bytes
146+
*/
147+
int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
148+
uint8_t const * const additional_input,
149+
uint32_t additionallen,
150+
uint8_t * const out,
39151
uint32_t outlen);
40152

153+
/**
154+
* @brief CTR-PRNG uninstantiate procedure
155+
* Zeroes the internal state of the supplied prng context
156+
* @return none
157+
* @param ctx IN/OUT -- the PRNG context
158+
*/
159+
void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx);
160+
41161
#ifdef __cplusplus
42162
}
43163
#endif

lib/source/ctr_prng.c

Lines changed: 117 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,54 @@
11
/* ctr_prng.c - TinyCrypt implementation of CTR-PRNG */
22

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+
330
#include <tinycrypt/ctr_prng.h>
431
#include <tinycrypt/utils.h>
532
#include <string.h>
633

7-
//todo comment
34+
/*
35+
* This PRNG is based on the CTR_DRBG described in Recommendation for Random
36+
* Number Generation Using Deterministic Random Bit Generators,
37+
* NIST SP 800-90A Rev. 1.
38+
*
39+
* Annotations to particular steps (e.g. 10.2.1.2 Step 1) refer to the steps
40+
* described in that document.
41+
*
42+
*/
43+
44+
/**
45+
* @brief Array incrementer
46+
* Treats the supplied array as one contiguous number (MSB in arr[0]), and
47+
* increments it by one
48+
* @return none
49+
* @param arr IN/OUT -- array to be incremented
50+
* @param len IN -- size of arr in bytes
51+
*/
852
static void arrInc(uint8_t arr[], uint32_t len)
953
{
1054
uint32_t i;
@@ -20,8 +64,16 @@ static void arrInc(uint8_t arr[], uint32_t len)
2064
}
2165
}
2266

23-
//todo comment
24-
static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const providedData[])
67+
/**
68+
* @brief CTR PRNG update
69+
* Updates the internal state of supplied the CTR PRNG context
70+
* increments it by one
71+
* @return none
72+
* @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long
73+
* @param ctx IN/OUT -- CTR PRNG state
74+
* @param providedData IN -- data used when updating the internal state
75+
*/
76+
static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData)
2577
{
2678
if (0 != ctx)
2779
{
@@ -70,37 +122,37 @@ static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const providedDa
70122
}
71123

72124
int32_t tc_ctr_prng_init(TCCtrPrng_t * const ctx,
73-
uint8_t const entropy[],
125+
uint8_t const * const entropy,
74126
uint32_t entropyLen,
75-
uint8_t const personalization[],
127+
uint8_t const * const personalization,
76128
uint32_t pLen)
77129
{
78130
int32_t result = TC_FAIL;
79131
uint32_t i;
80-
uint8_t persString[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
132+
uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
81133
uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
82134
uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U};
83135

84136
if (0 != personalization)
85137
{
86138
/* 10.2.1.3.1 step 1 */
87139
uint32_t len = pLen;
88-
if (len > sizeof persString)
140+
if (len > sizeof personalization_buf)
89141
{
90-
len = sizeof persString;
142+
len = sizeof personalization_buf;
91143
}
92144

93145
/* 10.2.1.3.1 step 2 */
94-
memcpy(persString, personalization, len);
146+
memcpy(personalization_buf, personalization, len);
95147
}
96148

97-
if ((0 != ctx) && (0 != entropy) && (entropyLen == sizeof seed_material))
149+
if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material))
98150
{
99151
/* 10.2.1.3.1 step 3 */
100152
memcpy(seed_material, entropy, sizeof seed_material);
101153
for (i = 0U; i < sizeof seed_material; i++)
102154
{
103-
seed_material[i] ^= persString[i];
155+
seed_material[i] ^= personalization_buf[i];
104156
}
105157

106158
/* 10.2.1.3.1 step 4 */
@@ -121,19 +173,39 @@ int32_t tc_ctr_prng_init(TCCtrPrng_t * const ctx,
121173
}
122174

123175
int32_t tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
124-
uint8_t const entropy[],
125-
uint32_t entropyLen)
176+
uint8_t const * const entropy,
177+
uint32_t entropyLen,
178+
uint8_t const * const additional_input,
179+
uint32_t additionallen)
126180
{
181+
uint32_t i;
127182
int32_t result = TC_FAIL;
183+
uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
184+
uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
185+
186+
if (0 != additional_input)
187+
{
188+
/* 10.2.1.4.1 step 1 */
189+
uint32_t len = additionallen;
190+
if (len > sizeof additional_input_buf)
191+
{
192+
len = sizeof additional_input_buf;
193+
}
194+
195+
/* 10.2.1.4.1 step 2 */
196+
memcpy(additional_input_buf, additional_input, len);
197+
}
128198

129-
//todo - add additional input support
130-
/*
131-
* 10.2.1.4.1 steps 1 - 3 not required - no additional input accepted by
132-
* this reseed function
133-
*/
134199
uint32_t seedlen = (uint32_t)TC_AES_KEY_SIZE + (uint32_t)TC_AES_BLOCK_SIZE;
135-
if ((0 != ctx) && (entropyLen == seedlen))
200+
if ((0 != ctx) && (entropyLen >= seedlen))
136201
{
202+
/* 10.2.1.4.1 step 3 */
203+
memcpy(seed_material, entropy, sizeof seed_material);
204+
for (i = 0U; i < sizeof seed_material; i++)
205+
{
206+
seed_material[i] ^= additional_input_buf[i];
207+
}
208+
137209
/* 10.2.1.4.1 step 4 */
138210
tc_ctr_prng_update(ctx, entropy);
139211

@@ -145,9 +217,10 @@ int32_t tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
145217
return result;
146218
}
147219

148-
//todo comment
149-
int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
150-
uint8_t out[],
220+
int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
221+
uint8_t const * const additional_input,
222+
uint32_t additionallen,
223+
uint8_t * const out,
151224
uint32_t outlen)
152225
{
153226
/* 2^48 - see section 10.2.1 */
@@ -167,8 +240,18 @@ int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
167240
}
168241
else
169242
{
170-
//todo - add additional input support
171-
/* 10.2.1.5.1 step 2 - no additional input supported, so no action */
243+
uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
244+
if (0 != additional_input)
245+
{
246+
/* 10.2.1.5.1 step 2 */
247+
uint32_t len = additionallen;
248+
if (len > sizeof additional_input_buf)
249+
{
250+
len = sizeof additional_input_buf;
251+
}
252+
memcpy(additional_input_buf, additional_input, len);
253+
tc_ctr_prng_update(ctx, additional_input_buf);
254+
}
172255

173256
/* 10.2.1.5.1 step 3 - implicit */
174257

@@ -209,6 +292,16 @@ int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
209292
return result;
210293
}
211294

295+
void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)
296+
{
297+
if (0 != ctx)
298+
{
299+
memset(ctx->key.words, 0x00, sizeof ctx->key.words);
300+
memset(ctx->V, 0x00, sizeof ctx->V);
301+
ctx->reseedCount = 0U;
302+
}
303+
}
304+
212305

213306

214307

0 commit comments

Comments
 (0)