Francois Berder / cyassl-lib

Dependents:   TLS_cyassl TLS_cyassl

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers random.c Source File

random.c

00001 /* random.c
00002  *
00003  * Copyright (C) 2006-2013 wolfSSL Inc.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * CyaSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023     #include <config.h>
00024 #endif
00025 
00026 /* on HPUX 11 you may need to install /dev/random see
00027    http://h20293.www2.hp.com/portal/swdepot/displayProductInfo.do?productNumber=KRNG11I
00028 
00029 */
00030 
00031 #include <cyassl/ctaocrypt/random.h>
00032 #include <cyassl/ctaocrypt/ctaoerror2.h>
00033 
00034 #ifdef NO_RC4
00035     #include <cyassl/ctaocrypt/sha256.h>
00036 
00037     #ifdef NO_INLINE
00038         #include <cyassl/ctaocrypt/misc.h>
00039     #else
00040         #define MISC_DUMM_FUNC misc_dummy_random
00041         #include <ctaocrypt/src/misc.c>
00042     #endif
00043 #endif
00044 
00045 #if defined(USE_WINDOWS_API)
00046     #ifndef _WIN32_WINNT
00047         #define _WIN32_WINNT 0x0400
00048     #endif
00049     #include <windows.h>
00050     #include <wincrypt.h>
00051 #else
00052     #if !defined(NO_DEV_RANDOM) && !defined(CYASSL_MDK_ARM) 
00053             #include <fcntl.h>
00054         #ifndef EBSNET
00055             #include <unistd.h>
00056         #endif
00057     #else
00058         /* include headers that may be needed to get good seed */
00059     #endif
00060 #endif /* USE_WINDOWS_API */
00061 
00062 
00063 #ifdef NO_RC4
00064 
00065 /* Start NIST DRBG code */
00066 
00067 #define OUTPUT_BLOCK_LEN (256/8)
00068 #define MAX_REQUEST_LEN  (0x1000)
00069 #define MAX_STRING_LEN   (0x100000000)
00070 #define RESEED_MAX       (0x100000000000LL)
00071 #define ENTROPY_SZ       256
00072 
00073 #define DBRG_SUCCESS 0
00074 #define DBRG_ERROR 1
00075 #define DBRG_NEED_RESEED 2
00076 
00077 
00078 enum {
00079     dbrgInitC     = 0,
00080     dbrgReseed    = 1,
00081     dbrgGenerateW = 2,
00082     dbrgGenerateH = 3,
00083     dbrgInitV
00084 };
00085 
00086 
00087 static int Hash_df(RNG* rng, byte* out, word32 outSz, byte type, byte* inA, word32 inASz,
00088                                byte* inB, word32 inBSz, byte* inC, word32 inCSz)
00089 {
00090     byte ctr;
00091     int i;
00092     int len;
00093     word32 bits = (outSz * 8); /* reverse byte order */
00094 
00095     #ifdef LITTLE_ENDIAN_ORDER
00096         bits = ByteReverseWord32(bits);
00097     #endif
00098     len = (outSz / SHA256_DIGEST_SIZE)
00099         + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0);
00100 
00101     for (i = 0, ctr = 1; i < len; i++, ctr++)
00102     {
00103         InitSha256(&rng->sha);
00104         Sha256Update(&rng->sha, &ctr, sizeof(ctr));
00105         Sha256Update(&rng->sha, (byte*)&bits, sizeof(bits));
00106         /* churning V is the only string that doesn't have 
00107          * the type added */
00108         if (type != dbrgInitV)
00109             Sha256Update(&rng->sha, &type, sizeof(type));
00110         Sha256Update(&rng->sha, inA, inASz);
00111         if (inB != NULL && inBSz > 0)
00112             Sha256Update(&rng->sha, inB, inBSz);
00113         if (inC != NULL && inCSz > 0)
00114             Sha256Update(&rng->sha, inC, inCSz);
00115         Sha256Final(&rng->sha, rng->digest);
00116 
00117         if (outSz > SHA256_DIGEST_SIZE) {
00118             XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE);
00119             outSz -= SHA256_DIGEST_SIZE;
00120             out += SHA256_DIGEST_SIZE;
00121         }
00122         else {
00123             XMEMCPY(out, rng->digest, outSz);
00124         }
00125     }
00126 
00127     return DBRG_SUCCESS;
00128 }
00129 
00130 
00131 static int Hash_DBRG_Reseed(RNG* rng, byte* entropy, word32 entropySz)
00132 {
00133     byte seed[DBRG_SEED_LEN];
00134 
00135     Hash_df(rng, seed, sizeof(seed), dbrgInitV, rng->V, sizeof(rng->V),
00136                                                   entropy, entropySz, NULL, 0);
00137     XMEMCPY(rng->V, seed, sizeof(rng->V));
00138     XMEMSET(seed, 0, sizeof(seed));
00139 
00140     Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, sizeof(rng->V),
00141                                                              NULL, 0, NULL, 0);
00142     rng->reseed_ctr = 1;
00143     return 0;
00144 }
00145 
00146 static INLINE void array_add_one(byte* data, word32 dataSz)
00147 {
00148     int i;
00149 
00150     for (i = dataSz - 1; i >= 0; i--)
00151     {
00152         data[i]++;
00153         if (data[i] != 0) break;
00154     }
00155 }
00156 
00157 static void Hash_gen(RNG* rng, byte* out, word32 outSz, byte* V)
00158 {
00159     byte data[DBRG_SEED_LEN];
00160     int i;
00161     int len = (outSz / SHA256_DIGEST_SIZE)
00162         + ((outSz % SHA256_DIGEST_SIZE) ? 1 : 0);
00163 
00164     XMEMCPY(data, V, sizeof(data));
00165     for (i = 0; i < len; i++) {
00166         InitSha256(&rng->sha);
00167         Sha256Update(&rng->sha, data, sizeof(data));
00168         Sha256Final(&rng->sha, rng->digest);
00169         if (outSz > SHA256_DIGEST_SIZE) {
00170             XMEMCPY(out, rng->digest, SHA256_DIGEST_SIZE);
00171             outSz -= SHA256_DIGEST_SIZE;
00172             out += SHA256_DIGEST_SIZE;
00173             array_add_one(data, DBRG_SEED_LEN);
00174         }
00175         else {
00176             XMEMCPY(out, rng->digest, outSz);
00177         }
00178     }
00179     XMEMSET(data, 0, sizeof(data));
00180 }
00181 
00182 
00183 static INLINE void array_add(byte* d, word32 dLen, byte* s, word32 sLen)
00184 {
00185     word16 carry = 0;
00186 
00187     if (dLen > 0 && sLen > 0 && dLen >= sLen) {
00188         int sIdx, dIdx;
00189             
00190         for (sIdx = sLen - 1, dIdx = dLen - 1; sIdx >= 0; dIdx--, sIdx--)
00191         {
00192             carry += d[dIdx] + s[sIdx];
00193             d[dIdx] = carry;
00194             carry >>= 8;
00195         } 
00196         if (dIdx > 0)
00197             d[dIdx] += carry;
00198     }
00199 }
00200 
00201 
00202 static int Hash_DBRG_Generate(RNG* rng, byte* out, word32 outSz)
00203 {
00204     int ret;
00205 
00206     if (rng->reseed_ctr != RESEED_MAX) {
00207         byte type = dbrgGenerateH;
00208 
00209         Hash_gen(rng, out, outSz, rng->V);
00210         InitSha256(&rng->sha);
00211         Sha256Update(&rng->sha, &type, sizeof(type));
00212         Sha256Update(&rng->sha, rng->V, sizeof(rng->V));
00213         Sha256Final(&rng->sha, rng->digest);
00214         array_add(rng->V, sizeof(rng->V), rng->digest, sizeof(rng->digest));
00215         array_add(rng->V, sizeof(rng->V), rng->C, sizeof(rng->C));
00216         array_add(rng->V, sizeof(rng->V),
00217                               (byte*)&rng->reseed_ctr, sizeof(rng->reseed_ctr));
00218         rng->reseed_ctr++;
00219         ret = DBRG_SUCCESS;
00220     }
00221     else {
00222         ret = DBRG_NEED_RESEED;
00223     }
00224     return ret;
00225 }
00226 
00227 
00228 static void Hash_DBRG_Instantiate(RNG* rng, byte* seed, word32 seedSz)
00229 {
00230     XMEMSET(rng, 0, sizeof(*rng));
00231     Hash_df(rng, rng->V, sizeof(rng->V), dbrgInitV, seed, seedSz, NULL, 0, NULL, 0);
00232     Hash_df(rng, rng->C, sizeof(rng->C), dbrgInitC, rng->V, sizeof(rng->V),
00233                                                              NULL, 0, NULL, 0);
00234     rng->reseed_ctr = 1;
00235 }
00236 
00237 
00238 static int Hash_DBRG_Uninstantiate(RNG* rng)
00239 {
00240     int result = DBRG_ERROR;
00241 
00242     if (rng != NULL) {
00243         XMEMSET(rng, 0, sizeof(*rng));
00244         result = DBRG_SUCCESS;
00245     }
00246 
00247     return result;
00248 }
00249 
00250 /* End NIST DRBG Code */
00251 
00252 
00253 
00254 /* Get seed and key cipher */
00255 int InitRng(RNG* rng)
00256 {
00257     byte entropy[ENTROPY_SZ];
00258     int  ret = DBRG_ERROR;
00259 
00260     if (GenerateSeed(&rng->seed, entropy, sizeof(entropy)) == 0) {
00261         Hash_DBRG_Instantiate(rng, entropy, sizeof(entropy));
00262         ret = DBRG_SUCCESS;
00263     }
00264     XMEMSET(entropy, 0, sizeof(entropy));
00265     return ret;
00266 }
00267 
00268 
00269 /* place a generated block in output */
00270 void RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
00271 {
00272     int ret;
00273 
00274     XMEMSET(output, 0, sz);
00275     ret = Hash_DBRG_Generate(rng, output, sz);
00276     if (ret == DBRG_NEED_RESEED) {
00277         byte entropy[ENTROPY_SZ];
00278         ret = GenerateSeed(&rng->seed, entropy, sizeof(entropy));
00279         if (ret == 0) {
00280             Hash_DBRG_Reseed(rng, entropy, sizeof(entropy));
00281             ret = Hash_DBRG_Generate(rng, output, sz);
00282         }
00283         else
00284             ret = DBRG_ERROR;
00285         XMEMSET(entropy, 0, sizeof(entropy));
00286     }
00287 }
00288 
00289 
00290 byte RNG_GenerateByte(RNG* rng)
00291 {
00292     byte b;
00293     RNG_GenerateBlock(rng, &b, 1);
00294 
00295     return b;
00296 }
00297 
00298 
00299 void FreeRng(RNG* rng)
00300 {
00301     Hash_DBRG_Uninstantiate(rng);
00302 }
00303 
00304 #else /* NO_RC4 */
00305 
00306 /* Get seed and key cipher */
00307 int InitRng(RNG* rng)
00308 {
00309     byte key[32];
00310     byte junk[256];
00311     int  ret;
00312 
00313 #ifdef HAVE_CAVIUM
00314     if (rng->magic == CYASSL_RNG_CAVIUM_MAGIC)
00315         return 0; 
00316 #endif
00317     ret = GenerateSeed(&rng->seed, key, sizeof(key));
00318 
00319     if (ret == 0) {
00320         Arc4SetKey(&rng->cipher, key, sizeof(key));
00321         RNG_GenerateBlock(rng, junk, sizeof(junk));  /* rid initial state */
00322     }
00323 
00324     return ret;
00325 }
00326 
00327 #ifdef HAVE_CAVIUM
00328     static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz);
00329 #endif
00330 
00331 /* place a generated block in output */
00332 void RNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
00333 {
00334 #ifdef HAVE_CAVIUM
00335     if (rng->magic == CYASSL_RNG_CAVIUM_MAGIC)
00336         return CaviumRNG_GenerateBlock(rng, output, sz); 
00337 #endif
00338     XMEMSET(output, 0, sz);
00339     Arc4Process(&rng->cipher, output, output, sz);
00340 }
00341 
00342 
00343 byte RNG_GenerateByte(RNG* rng)
00344 {
00345     byte b;
00346     RNG_GenerateBlock(rng, &b, 1);
00347 
00348     return b;
00349 }
00350 
00351 
00352 #ifdef HAVE_CAVIUM
00353 
00354 #include <cyassl/ctaocrypt/logging.h>
00355 #include "cavium_common.h"
00356 
00357 /* Initiliaze RNG for use with Nitrox device */
00358 int InitRngCavium(RNG* rng, int devId)
00359 {
00360     if (rng == NULL)
00361         return -1;
00362 
00363     rng->devId = devId;
00364     rng->magic = CYASSL_RNG_CAVIUM_MAGIC;
00365    
00366     return 0;
00367 }
00368 
00369 
00370 static void CaviumRNG_GenerateBlock(RNG* rng, byte* output, word32 sz)
00371 {
00372     word   offset = 0;
00373     word32 requestId;
00374 
00375     while (sz > CYASSL_MAX_16BIT) {
00376         word16 slen = (word16)CYASSL_MAX_16BIT;
00377         if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId,
00378                       rng->devId) != 0) {
00379             CYASSL_MSG("Cavium RNG failed");
00380         }
00381         sz     -= CYASSL_MAX_16BIT;
00382         offset += CYASSL_MAX_16BIT;
00383     }
00384     if (sz) {
00385         word16 slen = (word16)sz;
00386         if (CspRandom(CAVIUM_BLOCKING, slen, output + offset, &requestId,
00387                       rng->devId) != 0) {
00388             CYASSL_MSG("Cavium RNG failed");
00389         }
00390     }
00391 }
00392 
00393 #endif /* HAVE_CAVIUM */
00394 
00395 #endif /* NO_RC4 */
00396 
00397 
00398 #if defined(USE_WINDOWS_API)
00399 
00400 
00401 int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00402 {
00403     if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL,
00404                             CRYPT_VERIFYCONTEXT))
00405         return WINCRYPT_E;
00406 
00407     if (!CryptGenRandom(os->handle, sz, output))
00408         return CRYPTGEN_E;
00409 
00410     CryptReleaseContext(os->handle, 0);
00411 
00412     return 0;
00413 }
00414 
00415 
00416 #elif defined(HAVE_RTP_SYS) || defined(EBSNET)
00417 
00418 #include "rtprand.h"   /* rtp_rand () */
00419 #include "rtptime.h"   /* rtp_get_system_msec() */
00420 
00421 
00422 int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00423 {
00424     int i;
00425     rtp_srand(rtp_get_system_msec());
00426 
00427     for (i = 0; i < sz; i++ ) {
00428         output[i] = rtp_rand() % 256;
00429         if ( (i % 8) == 7)
00430             rtp_srand(rtp_get_system_msec());
00431     }
00432 
00433     return 0;
00434 }
00435 
00436 
00437 #elif defined(MICRIUM)
00438 
00439 int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00440 {
00441     #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
00442         NetSecure_InitSeed(output, sz);
00443     #endif
00444     return 0;
00445 }
00446 
00447 #elif defined(MBED)
00448 
00449 /* write a real one !!!, just for testing board */
00450 int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00451 {
00452     int i;
00453     for (i = 0; i < sz; i++ )
00454         output[i] = i;
00455 
00456     return 0;
00457 }
00458 
00459 #elif defined(MICROCHIP_PIC32)
00460 
00461 #include <peripheral/timer.h>
00462 
00463 /* uses the core timer, in nanoseconds to seed srand */
00464 int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00465 {
00466     int i;
00467     srand(ReadCoreTimer() * 25);
00468 
00469     for (i = 0; i < sz; i++ ) {
00470         output[i] = rand() % 256;
00471         if ( (i % 8) == 7)
00472             srand(ReadCoreTimer() * 25);
00473     }
00474 
00475     return 0;
00476 }
00477 
00478 #elif defined(CYASSL_SAFERTOS) || defined(CYASSL_LEANPSK)
00479 
00480 #warning "write a real random seed!!!!, just for testing now"
00481 
00482 int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00483 {
00484     word32 i;
00485     for (i = 0; i < sz; i++ )
00486         output[i] = i;
00487 
00488     (void)os;
00489 
00490     return 0;
00491 }
00492 
00493 #elif defined(FREESCALE_MQX)
00494 
00495     #ifdef FREESCALE_K70_RNGA
00496         /*
00497          * Generates a RNG seed using the Random Number Generator Accelerator
00498          * on the Kinetis K70. Documentation located in Chapter 37 of
00499          * K70 Sub-Family Reference Manual (see Note 3 in the README for link).
00500          */
00501         int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00502         {
00503             int i;
00504 
00505             /* turn on RNGA module */
00506             SIM_SCGC3 |= SIM_SCGC3_RNGA_MASK;
00507 
00508             /* set SLP bit to 0 - "RNGA is not in sleep mode" */
00509             RNG_CR &= ~RNG_CR_SLP_MASK;
00510 
00511             /* set HA bit to 1 - "security violations masked" */
00512             RNG_CR |= RNG_CR_HA_MASK;
00513 
00514             /* set GO bit to 1 - "output register loaded with data" */
00515             RNG_CR |= RNG_CR_GO_MASK;
00516 
00517             for (i = 0; i < sz; i++) {
00518 
00519                 /* wait for RNG FIFO to be full */
00520                 while((RNG_SR & RNG_SR_OREG_LVL(0xF)) == 0) {}
00521 
00522                 /* get value */
00523                 output[i] = RNG_OR;
00524             }
00525 
00526             return 0;
00527         }
00528     #else
00529         #warning "write a real random seed!!!!, just for testing now"
00530 
00531         int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00532         {
00533             int i;
00534             for (i = 0; i < sz; i++ )
00535                 output[i] = i;
00536 
00537             return 0;
00538         }
00539     #endif /* FREESCALE_K70_RNGA */
00540 
00541 #elif defined(STM32F2_RNG)
00542     #undef RNG
00543     #include "stm32f2xx_rng.h"
00544     #include "stm32f2xx_rcc.h"
00545     /*
00546      * Generate a RNG seed using the hardware random number generator 
00547      * on the STM32F2. Documentation located in STM32F2xx Standard Peripheral 
00548      * Library document (See note in README).
00549      */
00550     int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00551     {
00552         int i;
00553 
00554         /* enable RNG clock source */
00555         RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
00556 
00557         /* enable RNG peripheral */
00558         RNG_Cmd(ENABLE);
00559 
00560         for (i = 0; i < sz; i++) {
00561             /* wait until RNG number is ready */
00562             while(RNG_GetFlagStatus(RNG_FLAG_DRDY)== RESET) { }
00563 
00564             /* get value */
00565             output[i] = RNG_GetRandomNumber();
00566         }
00567 
00568         return 0;
00569     }
00570 #elif defined(CYASSL_LPC43xx) || defined(CYASSL_STM32F2xx)
00571 
00572     #warning "write a real random seed!!!!, just for testing now"
00573 
00574     int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00575     {
00576         int i;
00577 
00578         for (i = 0; i < sz; i++ )
00579             output[i] = i;
00580 
00581         return 0;
00582     }
00583 
00584 #elif defined(NO_DEV_RANDOM)
00585 
00586 #error "you need to write an os specific GenerateSeed() here"
00587 
00588 /*
00589 int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00590 {
00591     return 0;
00592 }
00593 */
00594 
00595 
00596 #else /* !USE_WINDOWS_API && !HAVE_RPT_SYS && !MICRIUM && !NO_DEV_RANDOM */
00597 
00598 
00599 /* may block */
00600 int GenerateSeed(OS_Seed* os, byte* output, word32 sz)
00601 {
00602     int ret = 0;
00603 
00604     os->fd = open("/dev/urandom",O_RDONLY);
00605     if (os->fd == -1) {
00606         /* may still have /dev/random */
00607         os->fd = open("/dev/random",O_RDONLY);
00608         if (os->fd == -1)
00609             return OPEN_RAN_E;
00610     }
00611 
00612     while (sz) {
00613         int len = (int)read(os->fd, output, sz);
00614         if (len == -1) { 
00615             ret = READ_RAN_E;
00616             break;
00617         }
00618 
00619         sz     -= len;
00620         output += len;
00621 
00622         if (sz) {
00623 #ifdef BLOCKING
00624             sleep(0);             /* context switch */
00625 #else
00626             ret = RAN_BLOCK_E;
00627             break;
00628 #endif
00629         }
00630     }
00631     close(os->fd);
00632 
00633     return ret;
00634 }
00635 
00636 #endif /* USE_WINDOWS_API */
00637