aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorChris Morrison <[email protected]>2016-02-19 16:52:16 -0800
committerChris Morrison <[email protected]>2016-02-19 16:52:16 -0800
commit853e01c70e7f2742f934ae9298a42c7e536f4f7e (patch)
treeb2682f3a9a4942197a85d3835942ff283b4892f3 /lib
parent4860c470848dde6b4ff90e2eed48658c330b3864 (diff)
Adding support for additional input when reseeding/generating ctr prngs. Also added documentation
Diffstat (limited to 'lib')
-rw-r--r--lib/include/tinycrypt/ctr_prng.h138
-rw-r--r--lib/source/ctr_prng.c141
2 files changed, 246 insertions, 33 deletions
diff --git a/lib/include/tinycrypt/ctr_prng.h b/lib/include/tinycrypt/ctr_prng.h
index 17eb0a5..2d3f6f7 100644
--- a/lib/include/tinycrypt/ctr_prng.h
+++ b/lib/include/tinycrypt/ctr_prng.h
@@ -1,5 +1,61 @@
/* ctr_prng.h - TinyCrypt interface to an CTR-PRNG implementation */
+/*
+ * Copyright (c) 2016, Chris Morrison
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief Interface to an CTR-PRNG implementation.
+ *
+ * Overview: A pseudo-random number generator (PRNG) generates a sequence
+ * of numbers that have a distribution close to the one expected
+ * for a sequence of truly random numbers. The NIST Special
+ * Publication 800-90A specifies several mechanisms to generate
+ * sequences of pseudo random numbers, including the CTR-PRNG one
+ * which is based on AES. TinyCrypt implements CTR-PRNG with
+ * AES-128.
+ *
+ * Security: A cryptographically secure PRNG depends on the existence of an
+ * entropy source to provide a truly random seed as well as the
+ * security of the primitives used as the building blocks (AES-128
+ * in this instance).
+ *
+ * Requires: - AES-128
+ *
+ * Usage: 1) call tc_ctr_prng_init to seed the prng context
+ *
+ * 2) call tc_ctr_prng_reseed to mix in additional entropy into
+ * the prng context
+ *
+ * 3) call tc_ctr_prng_generate to output the pseudo-random data
+ *
+ * 4) call tc_ctr_prng_uninstantiate to zero out the prng context
+ */
+
#ifndef __TC_CTR_PRNG_H__
#define __TC_CTR_PRNG_H__
@@ -17,27 +73,91 @@ typedef struct
/* updated whenever the PRNG is reseeded */
struct tc_aes_key_sched_struct key;
- /* number of requests since initialisation/reseeding */
+ /* number of requests since initialization/reseeding */
uint64_t reseedCount;
} TCCtrPrng_t;
-//todo comment
+/**
+ * @brief CTR-PRNG initialization procedure
+ * Initializes prng context with entropy and personalization string (if any)
+ * @return returns TC_SUCCESS (1)
+ * returns TC_FAIL (0) if:
+ * ctx == NULL,
+ * entropy == NULL,
+ * entropyLen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE)
+ * @note Only the first (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes of
+ * both the entropy and personalization inputs are used -
+ * supplying additional bytes has no effect.
+ * @param ctx IN/OUT -- the PRNG context to initialize
+ * @param entropy IN -- entropy used to seed the PRNG
+ * @param entropyLen IN -- entropy length in bytes
+ * @param personalization IN -- personalization string used to seed the PRNG
+ * (may be null)
+ * @param plen IN -- personalization length in bytes
+ *
+ */
int32_t tc_ctr_prng_init(TCCtrPrng_t * const ctx,
- uint8_t const entropy[],
+ uint8_t const * const entropy,
uint32_t entropyLen,
- uint8_t const personalization[],
+ uint8_t const * const personalization,
uint32_t pLen);
-//todo comment
+/**
+ * @brief CTR-PRNG reseed procedure
+ * Mixes entropy and additional_input into the prng context
+ * @return returns TC_SUCCESS (1)
+ * returns TC_FAIL (0) if:
+ * ctx == NULL,
+ * entropy == NULL,
+ * entropylen < (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE)
+ * @note It is better to reseed an existing prng context rather than
+ * re-initialise, so that any existing entropy in the context is
+ * presereved. This offers some protection against undetected failures
+ * of the entropy source.
+ * @note Assumes tc_ctr_prng_init has been called for ctx
+ * @param ctx IN/OUT -- the PRNG state
+ * @param entropy IN -- entropy to mix into the prng
+ * @param entropylen IN -- length of entropy in bytes
+ * @param additional_input IN -- additional input to the prng (may be null)
+ * @param additionallen IN -- additional input length in bytes
+ */
int32_t tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
- uint8_t const entropy[],
- uint32_t entropyLen);
+ uint8_t const * const entropy,
+ uint32_t entropyLen,
+ uint8_t const * const additional_input,
+ uint32_t additionallen);
-int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
- uint8_t out[],
+/**
+ * @brief CTR-PRNG generate procedure
+ * Generates outlen pseudo-random bytes into out buffer, updates prng
+ * @return returns TC_SUCCESS (1)
+ * returns TC_RESEED_REQ (-1) if a reseed is needed
+ * returns TC_FAIL (0) if:
+ * ctx == NULL,
+ * out == NULL,
+ * outlen >= 2^16
+ * @note Assumes tc_ctr_prng_init has been called for ctx
+ * @param ctx IN/OUT -- the PRNG context
+ * @param additional_input IN -- additional input to the prng (may be null)
+ * @param additionallen IN -- additional input length in bytes
+ * @param out IN/OUT -- buffer to receive output
+ * @param outlen IN -- size of out buffer in bytes
+ */
+int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
+ uint8_t const * const additional_input,
+ uint32_t additionallen,
+ uint8_t * const out,
uint32_t outlen);
+/**
+ * @brief CTR-PRNG uninstantiate procedure
+ * Zeroes the internal state of the supplied prng context
+ * @return none
+ * @param ctx IN/OUT -- the PRNG context
+ */
+void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/source/ctr_prng.c b/lib/source/ctr_prng.c
index e2aa429..d52dc5d 100644
--- a/lib/source/ctr_prng.c
+++ b/lib/source/ctr_prng.c
@@ -1,10 +1,54 @@
/* ctr_prng.c - TinyCrypt implementation of CTR-PRNG */
+/*
+ * Copyright (c) 2016, Chris Morrison
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
#include <tinycrypt/ctr_prng.h>
#include <tinycrypt/utils.h>
#include <string.h>
-//todo comment
+/*
+ * This PRNG is based on the CTR_DRBG described in Recommendation for Random
+ * Number Generation Using Deterministic Random Bit Generators,
+ * NIST SP 800-90A Rev. 1.
+ *
+ * Annotations to particular steps (e.g. 10.2.1.2 Step 1) refer to the steps
+ * described in that document.
+ *
+ */
+
+/**
+ * @brief Array incrementer
+ * Treats the supplied array as one contiguous number (MSB in arr[0]), and
+ * increments it by one
+ * @return none
+ * @param arr IN/OUT -- array to be incremented
+ * @param len IN -- size of arr in bytes
+ */
static void arrInc(uint8_t arr[], uint32_t len)
{
uint32_t i;
@@ -20,8 +64,16 @@ static void arrInc(uint8_t arr[], uint32_t len)
}
}
-//todo comment
-static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const providedData[])
+/**
+ * @brief CTR PRNG update
+ * Updates the internal state of supplied the CTR PRNG context
+ * increments it by one
+ * @return none
+ * @note Assumes: providedData is (TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE) bytes long
+ * @param ctx IN/OUT -- CTR PRNG state
+ * @param providedData IN -- data used when updating the internal state
+ */
+static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData)
{
if (0 != ctx)
{
@@ -70,14 +122,14 @@ static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const providedDa
}
int32_t tc_ctr_prng_init(TCCtrPrng_t * const ctx,
- uint8_t const entropy[],
+ uint8_t const * const entropy,
uint32_t entropyLen,
- uint8_t const personalization[],
+ uint8_t const * const personalization,
uint32_t pLen)
{
int32_t result = TC_FAIL;
uint32_t i;
- uint8_t persString[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
+ uint8_t personalization_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
uint8_t zeroArr[TC_AES_BLOCK_SIZE] = {0U};
@@ -85,22 +137,22 @@ int32_t tc_ctr_prng_init(TCCtrPrng_t * const ctx,
{
/* 10.2.1.3.1 step 1 */
uint32_t len = pLen;
- if (len > sizeof persString)
+ if (len > sizeof personalization_buf)
{
- len = sizeof persString;
+ len = sizeof personalization_buf;
}
/* 10.2.1.3.1 step 2 */
- memcpy(persString, personalization, len);
+ memcpy(personalization_buf, personalization, len);
}
- if ((0 != ctx) && (0 != entropy) && (entropyLen == sizeof seed_material))
+ if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material))
{
/* 10.2.1.3.1 step 3 */
memcpy(seed_material, entropy, sizeof seed_material);
for (i = 0U; i < sizeof seed_material; i++)
{
- seed_material[i] ^= persString[i];
+ seed_material[i] ^= personalization_buf[i];
}
/* 10.2.1.3.1 step 4 */
@@ -121,19 +173,39 @@ int32_t tc_ctr_prng_init(TCCtrPrng_t * const ctx,
}
int32_t tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
- uint8_t const entropy[],
- uint32_t entropyLen)
+ uint8_t const * const entropy,
+ uint32_t entropyLen,
+ uint8_t const * const additional_input,
+ uint32_t additionallen)
{
+ uint32_t i;
int32_t result = TC_FAIL;
+ uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
+ uint8_t seed_material[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE];
+
+ if (0 != additional_input)
+ {
+ /* 10.2.1.4.1 step 1 */
+ uint32_t len = additionallen;
+ if (len > sizeof additional_input_buf)
+ {
+ len = sizeof additional_input_buf;
+ }
+
+ /* 10.2.1.4.1 step 2 */
+ memcpy(additional_input_buf, additional_input, len);
+ }
- //todo - add additional input support
- /*
- * 10.2.1.4.1 steps 1 - 3 not required - no additional input accepted by
- * this reseed function
- */
uint32_t seedlen = (uint32_t)TC_AES_KEY_SIZE + (uint32_t)TC_AES_BLOCK_SIZE;
- if ((0 != ctx) && (entropyLen == seedlen))
+ if ((0 != ctx) && (entropyLen >= seedlen))
{
+ /* 10.2.1.4.1 step 3 */
+ memcpy(seed_material, entropy, sizeof seed_material);
+ for (i = 0U; i < sizeof seed_material; i++)
+ {
+ seed_material[i] ^= additional_input_buf[i];
+ }
+
/* 10.2.1.4.1 step 4 */
tc_ctr_prng_update(ctx, entropy);
@@ -145,9 +217,10 @@ int32_t tc_ctr_prng_reseed(TCCtrPrng_t * const ctx,
return result;
}
-//todo comment
-int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
- uint8_t out[],
+int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
+ uint8_t const * const additional_input,
+ uint32_t additionallen,
+ uint8_t * const out,
uint32_t outlen)
{
/* 2^48 - see section 10.2.1 */
@@ -167,8 +240,18 @@ int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
}
else
{
- //todo - add additional input support
- /* 10.2.1.5.1 step 2 - no additional input supported, so no action */
+ uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U};
+ if (0 != additional_input)
+ {
+ /* 10.2.1.5.1 step 2 */
+ uint32_t len = additionallen;
+ if (len > sizeof additional_input_buf)
+ {
+ len = sizeof additional_input_buf;
+ }
+ memcpy(additional_input_buf, additional_input, len);
+ tc_ctr_prng_update(ctx, additional_input_buf);
+ }
/* 10.2.1.5.1 step 3 - implicit */
@@ -209,6 +292,16 @@ int32_t tc_ctr_prng_generate(TCCtrPrng_t * const ctx,
return result;
}
+void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx)
+{
+ if (0 != ctx)
+ {
+ memset(ctx->key.words, 0x00, sizeof ctx->key.words);
+ memset(ctx->V, 0x00, sizeof ctx->V);
+ ctx->reseedCount = 0U;
+ }
+}
+