Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers yarrow.c Source File

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