ctr_prng.c 7.8 KB

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