Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
yarrow.c
Go to the documentation of this file.
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
