David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 53 | static void arrInc(uint8_t arr[], unsigned int len) |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 54 | { |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 55 | unsigned int i; |
| 56 | if (0 != arr) { |
| 57 | for (i = len; i > 0U; i--) { |
| 58 | if (++arr[i-1] != 0U) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | */ |
| 74 | static void tc_ctr_prng_update(TCCtrPrng_t * const ctx, uint8_t const * const providedData) |
| 75 | { |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 76 | if (0 != ctx) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 77 | /* 10.2.1.2 step 1 */ |
| 78 | uint8_t temp[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE]; |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 79 | unsigned int len = 0U; |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 80 | |
| 81 | /* 10.2.1.2 step 2 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 82 | while (len < sizeof temp) { |
| 83 | unsigned int blocklen = sizeof(temp) - len; |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 90 | if (blocklen > TC_AES_BLOCK_SIZE) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 102 | if (0 != providedData) { |
| 103 | unsigned int i; |
| 104 | for (i = 0U; i < sizeof temp; i++) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 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) |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 122 | { |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 123 | int result = TC_CRYPTO_FAIL; |
| 124 | unsigned int i; |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 129 | if (0 != personalization) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 130 | /* 10.2.1.3.1 step 1 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 131 | unsigned int len = pLen; |
| 132 | if (len > sizeof personalization_buf) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 133 | len = sizeof personalization_buf; |
| 134 | } |
| 135 | |
| 136 | /* 10.2.1.3.1 step 2 */ |
| 137 | memcpy(personalization_buf, personalization, len); |
| 138 | } |
| 139 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 140 | if ((0 != ctx) && (0 != entropy) && (entropyLen >= sizeof seed_material)) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 141 | /* 10.2.1.3.1 step 3 */ |
| 142 | memcpy(seed_material, entropy, sizeof seed_material); |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 143 | for (i = 0U; i < sizeof seed_material; i++) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 164 | int tc_ctr_prng_reseed(TCCtrPrng_t * const ctx, |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 165 | uint8_t const * const entropy, |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 166 | unsigned int entropyLen, |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 167 | uint8_t const * const additional_input, |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 168 | unsigned int additionallen) |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 169 | { |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 170 | unsigned int i; |
| 171 | int result = TC_CRYPTO_FAIL; |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 175 | if (0 != additional_input) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 176 | /* 10.2.1.4.1 step 1 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 177 | unsigned int len = additionallen; |
| 178 | if (len > sizeof additional_input_buf) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 186 | unsigned int seedlen = (unsigned int)TC_AES_KEY_SIZE + (unsigned int)TC_AES_BLOCK_SIZE; |
| 187 | if ((0 != ctx) && (entropyLen >= seedlen)) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 188 | /* 10.2.1.4.1 step 3 */ |
| 189 | memcpy(seed_material, entropy, sizeof seed_material); |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 190 | for (i = 0U; i < sizeof seed_material; i++) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 205 | int tc_ctr_prng_generate(TCCtrPrng_t * const ctx, |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 206 | uint8_t const * const additional_input, |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 207 | unsigned int additionallen, |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 208 | uint8_t * const out, |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 209 | unsigned int outlen) |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 215 | static const unsigned int MAX_BYTES_PER_REQ = 65536U; |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 216 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 217 | unsigned int result = TC_CRYPTO_FAIL; |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 218 | |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 219 | if ((0 != ctx) && (0 != out) && (outlen < MAX_BYTES_PER_REQ)) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 220 | /* 10.2.1.5.1 step 1 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 221 | if (ctx->reseedCount > MAX_REQS_BEFORE_RESEED) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 222 | result = TC_CTR_PRNG_RESEED_REQ; |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 223 | } else { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 224 | uint8_t additional_input_buf[TC_AES_KEY_SIZE + TC_AES_BLOCK_SIZE] = {0U}; |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 225 | if (0 != additional_input) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 226 | /* 10.2.1.5.1 step 2 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 227 | unsigned int len = additionallen; |
| 228 | if (len > sizeof additional_input_buf) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 238 | unsigned int len = 0U; |
| 239 | while (len < outlen) { |
| 240 | unsigned int blocklen = outlen - len; |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 */ |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 250 | if (blocklen > TC_AES_BLOCK_SIZE) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | |
| 272 | void tc_ctr_prng_uninstantiate(TCCtrPrng_t * const ctx) |
| 273 | { |
Fabio Utzig | 3efe6b6 | 2017-09-22 16:03:24 -0300 | [diff] [blame] | 274 | if (0 != ctx) { |
David Brown | fecda2d | 2017-09-07 10:20:34 -0600 | [diff] [blame] | 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 | |
| 281 | |
| 282 | |
| 283 | |