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.
Dependents: TLS_cyassl TLS_cyassl
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
Generated on Thu Jul 14 2022 20:26:03 by
1.7.2