Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
yarrow.c
00001 /** 00002 * @file yarrow.c 00003 * @brief Yarrow PRNG 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneSSL Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <string.h> 00034 #include "crypto.h" 00035 #include "yarrow.h" 00036 #include "debug.h" 00037 00038 //Check crypto library configuration 00039 #if (YARROW_SUPPORT == ENABLED) 00040 00041 //Common interface for PRNG algorithms 00042 const PrngAlgo yarrowPrngAlgo = 00043 { 00044 "Yarrow", 00045 sizeof(YarrowContext), 00046 (PrngAlgoInit) yarrowInit, 00047 (PrngAlgoRelease) yarrowRelease, 00048 (PrngAlgoSeed) yarrowSeed, 00049 (PrngAlgoAddEntropy) yarrowAddEntropy, 00050 (PrngAlgoRead) yarrowRead 00051 }; 00052 00053 00054 /** 00055 * @brief Initialize PRNG context 00056 * @param[in] context Pointer to the PRNG context to initialize 00057 * @return Error code 00058 **/ 00059 00060 error_t yarrowInit(YarrowContext *context) 00061 { 00062 //Clear PRNG state 00063 memset(context, 0, sizeof(YarrowContext)); 00064 00065 //Create a mutex to prevent simultaneous access to the PRNG state 00066 if(!osCreateMutex(&context->mutex)) 00067 { 00068 //Failed to create mutex 00069 return ERROR_OUT_OF_RESOURCES; 00070 } 00071 00072 //Initialize hash contexts 00073 sha256Init(&context->fastPool); 00074 sha256Init(&context->slowPool); 00075 00076 //The PRNG is not ready to generate random data 00077 context->ready = FALSE; 00078 00079 //Successful initialization 00080 return NO_ERROR; 00081 } 00082 00083 00084 /** 00085 * @brief Release PRNG context 00086 * @param[in] context Pointer to the PRNG context 00087 **/ 00088 00089 void yarrowRelease(YarrowContext *context) 00090 { 00091 //Release previously allocated resources 00092 osDeleteMutex(&context->mutex); 00093 00094 //Clear PRNG state 00095 memset(context, 0, sizeof(YarrowContext)); 00096 } 00097 00098 00099 /** 00100 * @brief Seed the PRNG state 00101 * @param[in] context Pointer to the PRNG context 00102 * @param[in] input Pointer to the input data 00103 * @param[in] length Length of the input data 00104 * @return Error code 00105 **/ 00106 00107 error_t yarrowSeed(YarrowContext *context, const uint8_t *input, size_t length) 00108 { 00109 //Check parameters 00110 if(length < sizeof(context->key)) 00111 return ERROR_INVALID_PARAMETER; 00112 00113 //Add entropy to the fast pool 00114 sha256Update(&context->fastPool, input, length); 00115 //Reseed from the fast pool 00116 yarrowFastReseed(context); 00117 00118 //Successful processing 00119 return NO_ERROR; 00120 } 00121 00122 00123 /** 00124 * @brief Add entropy to the PRNG state 00125 * @param[in] context Pointer to the PRNG context 00126 * @param[in] source Entropy source identifier 00127 * @param[in] input Pointer to the input data 00128 * @param[in] length Length of the input data 00129 * @param[in] entropy Actual number of bits of entropy 00130 * @return Error code 00131 **/ 00132 00133 error_t yarrowAddEntropy(YarrowContext *context, uint_t source, 00134 const uint8_t *input, size_t length, size_t entropy) 00135 { 00136 uint_t i; 00137 uint_t k; 00138 00139 //Check parameters 00140 if(source >= YARROW_N) 00141 return ERROR_INVALID_PARAMETER; 00142 00143 //Acquire exclusive access to the PRNG state 00144 osAcquireMutex(&context->mutex); 00145 00146 //Entropy from samples are collected into two pools 00147 if(context->currentPool[source] == YARROW_FAST_POOL_ID) 00148 { 00149 //Each pool contains running hash of all inputs since last reseed 00150 sha256Update(&context->fastPool, input, length); 00151 //Estimate the amount of entropy we have collected thus far 00152 context->fastPoolEntropy[source] += entropy; 00153 00154 //Reseed when any source estimate reaches 100 bits 00155 if(context->fastPoolEntropy[source] >= YARROW_FAST_THRESHOLD) 00156 yarrowFastReseed(context); 00157 00158 //The samples from each source alternate between the two pools 00159 context->currentPool[source] = YARROW_SLOW_POOL_ID; 00160 } 00161 else 00162 { 00163 //Each pool contains running hash of all inputs since last reseed 00164 sha256Update(&context->slowPool, input, length); 00165 //Estimate the amount of entropy we have collected thus far 00166 context->slowPoolEntropy[source] += entropy; 00167 00168 //Prevent overflows while adding up the entropy estimate 00169 if(context->slowPoolEntropy[source] >= YARROW_SLOW_THRESHOLD) 00170 context->slowPoolEntropy[source] = YARROW_SLOW_THRESHOLD; 00171 00172 //At least two different sources must be over 160 bits in the slow 00173 //pool before the slow pool reseeds 00174 for(k = 0, i = 0; i < YARROW_N; i++) 00175 { 00176 //Check whether the current source has hit the threshold 00177 if(context->slowPoolEntropy[i] >= YARROW_SLOW_THRESHOLD) 00178 k++; 00179 } 00180 00181 //Reseed from the slow pool? 00182 if(k >= YARROW_K) 00183 yarrowSlowReseed(context); 00184 00185 //The samples from each source alternate between the two pools 00186 context->currentPool[source] = YARROW_FAST_POOL_ID; 00187 } 00188 00189 //Release exclusive access to the PRNG state 00190 osReleaseMutex(&context->mutex); 00191 00192 //Successful processing 00193 return NO_ERROR; 00194 } 00195 00196 00197 /** 00198 * @brief Read random data 00199 * @param[in] context Pointer to the PRNG context 00200 * @param[out] output Buffer where to store the output data 00201 * @param[in] length Desired length in bytes 00202 * @return Error code 00203 **/ 00204 00205 error_t yarrowRead(YarrowContext *context, uint8_t *output, size_t length) 00206 { 00207 size_t n; 00208 uint8_t buffer[AES_BLOCK_SIZE]; 00209 00210 //Make sure that the PRNG has been properly seeded 00211 if(!context->ready) 00212 return ERROR_PRNG_NOT_READY; 00213 00214 //Acquire exclusive access to the PRNG state 00215 osAcquireMutex(&context->mutex); 00216 00217 //Generate random data in a block-by-block fashion 00218 while(length > 0) 00219 { 00220 //Number of bytes to process at a time 00221 n = MIN(length, AES_BLOCK_SIZE); 00222 00223 //Generate a random block 00224 yarrowGenerateBlock(context, buffer); 00225 //Copy data to the output buffer 00226 memcpy(output, buffer, n); 00227 00228 //We keep track of how many blocks we have output 00229 context->blockCount++; 00230 00231 //Next block 00232 output += n; 00233 length -= n; 00234 } 00235 00236 //Apply generator gate? 00237 if(context->blockCount >= YARROW_PG) 00238 { 00239 //Generate some random bytes 00240 yarrowGenerateBlock(context, context->key); 00241 //Use them as the new key 00242 aesInit(&context->cipherContext, context->key, sizeof(context->key)); 00243 00244 //Reset block counter 00245 context->blockCount = 0; 00246 } 00247 00248 //Release exclusive access to the PRNG state 00249 osReleaseMutex(&context->mutex); 00250 00251 //Successful processing 00252 return NO_ERROR; 00253 } 00254 00255 00256 /** 00257 * @brief Generate a random block of data 00258 * @param[in] context Pointer to the PRNG context 00259 * @param[out] output Buffer where to store the output block 00260 **/ 00261 00262 void yarrowGenerateBlock(YarrowContext *context, uint8_t *output) 00263 { 00264 int_t i; 00265 00266 //Encrypt counter block 00267 aesEncryptBlock(&context->cipherContext, context->counter, output); 00268 00269 //Increment counter value 00270 for(i = AES_BLOCK_SIZE - 1; i >= 0; i--) 00271 { 00272 //Increment the current byte and propagate the carry if necessary 00273 if(++(context->counter[i]) != 0) 00274 break; 00275 } 00276 } 00277 00278 00279 /** 00280 * @brief Reseed from the fast pool 00281 * @param[in] context Pointer to the PRNG context 00282 **/ 00283 00284 void yarrowFastReseed(YarrowContext *context) 00285 { 00286 size_t i; 00287 00288 //Reseeding from the fast pool use the current key and the hash of all 00289 //inputs to the fast pool since the last reseed, to generate a new key 00290 sha256Update(&context->fastPool, context->key, sizeof(context->key)); 00291 sha256Final(&context->fastPool, context->key); 00292 00293 //Set the new key 00294 aesInit(&context->cipherContext, context->key, sizeof(context->key)); 00295 00296 //Define the new value of the counter 00297 memset(context->counter, 0, sizeof(context->counter)); 00298 aesEncryptBlock(&context->cipherContext, context->counter, context->counter); 00299 00300 //Reset the hash context 00301 sha256Init(&context->fastPool); 00302 00303 //The entropy estimates for the fast pool are all reset to zero 00304 for(i = 0; i < YARROW_N; i++) 00305 context->fastPoolEntropy[i] = 0; 00306 00307 //The PRNG is ready to generate random data 00308 context->ready = TRUE; 00309 } 00310 00311 00312 /** 00313 * @brief Reseed from the slow pool 00314 * @param[in] context Pointer to the PRNG context 00315 **/ 00316 00317 void yarrowSlowReseed(YarrowContext *context) 00318 { 00319 size_t i; 00320 00321 //Compute the hash of all inputs to the fast pool 00322 sha256Final(&context->fastPool, NULL); 00323 00324 //Reseeding from the slow pool use the current key, the hash of all inputs to the 00325 //fast pool and the hash of all inputs to the slow pool, to generate a new key 00326 sha256Update(&context->slowPool, context->key, sizeof(context->key)); 00327 sha256Update(&context->slowPool, context->fastPool.digest, SHA256_DIGEST_SIZE); 00328 sha256Final(&context->slowPool, context->key); 00329 00330 //Set the new key 00331 aesInit(&context->cipherContext, context->key, sizeof(context->key)); 00332 00333 //Define the new value of the counter 00334 memset(context->counter, 0, sizeof(context->counter)); 00335 aesEncryptBlock(&context->cipherContext, context->counter, context->counter); 00336 00337 //Reset the hash contexts 00338 sha256Init(&context->fastPool); 00339 sha256Init(&context->slowPool); 00340 00341 //The entropy estimates for both pools are reset to zero 00342 for(i = 0; i < YARROW_N; i++) 00343 { 00344 context->fastPoolEntropy[i] = 0; 00345 context->slowPoolEntropy[i] = 0; 00346 } 00347 00348 //The PRNG is ready to generate random data 00349 context->ready = TRUE; 00350 } 00351 00352 #endif 00353
Generated on Tue Jul 12 2022 17:10:18 by
1.7.2