1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-21 10:26:06 +03:00

Get random bytes from hardware RNG

This commit is contained in:
Ivan Grokhotkov 2015-12-02 23:49:49 +03:00
parent 6830d98c7f
commit 34ff4421d2

View File

@ -1,18 +1,18 @@
/* /*
* Copyright (c) 2007, Cameron Rich * Copyright (c) 2007, Cameron Rich
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* * Redistributions of source code must retain the above copyright notice, * * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, * * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation * this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. * and/or other materials provided with the distribution.
* * Neither the name of the axTLS project nor the names of its contributors * * Neither the name of the axTLS project nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
@ -44,6 +44,7 @@
#ifdef ESP8266 #ifdef ESP8266
#define CONFIG_SSL_SKELETON_MODE 1 #define CONFIG_SSL_SKELETON_MODE 1
uint32_t phy_get_rand();
#endif #endif
#if defined(CONFIG_USE_DEV_URANDOM) #if defined(CONFIG_USE_DEV_URANDOM)
@ -63,20 +64,20 @@ static uint8_t entropy_pool[ENTROPY_POOL_SIZE];
const char * const unsupported_str = "Error: Feature not supported\n"; const char * const unsupported_str = "Error: Feature not supported\n";
#ifndef CONFIG_SSL_SKELETON_MODE #ifndef CONFIG_SSL_SKELETON_MODE
/** /**
* Retrieve a file and put it into memory * Retrieve a file and put it into memory
* @return The size of the file, or -1 on failure. * @return The size of the file, or -1 on failure.
*/ */
int get_file(const char *filename, uint8_t **buf) int get_file(const char *filename, uint8_t **buf)
{ {
int total_bytes = 0; int total_bytes = 0;
int bytes_read = 0; int bytes_read = 0;
int filesize; int filesize;
FILE *stream = fopen(filename, "rb"); FILE *stream = fopen(filename, "rb");
if (stream == NULL) if (stream == NULL)
{ {
#ifdef CONFIG_SSL_FULL_MODE #ifdef CONFIG_SSL_FULL_MODE
printf("file '%s' does not exist\n", filename); TTY_FLUSH(); printf("file '%s' does not exist\n", filename); TTY_FLUSH();
#endif #endif
return -1; return -1;
@ -93,7 +94,7 @@ int get_file(const char *filename, uint8_t **buf)
bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream); bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
total_bytes += bytes_read; total_bytes += bytes_read;
} while (total_bytes < filesize && bytes_read > 0); } while (total_bytes < filesize && bytes_read > 0);
fclose(stream); fclose(stream);
return filesize; return filesize;
} }
@ -110,25 +111,26 @@ EXP_FUNC void STDCALL RNG_initialize()
#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
rng_fd = ax_open("/dev/urandom", O_RDONLY); rng_fd = ax_open("/dev/urandom", O_RDONLY);
#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB) #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
if (!CryptAcquireContext(&gCryptProv, if (!CryptAcquireContext(&gCryptProv,
NULL, NULL, PROV_RSA_FULL, 0)) NULL, NULL, PROV_RSA_FULL, 0))
{ {
if (GetLastError() == NTE_BAD_KEYSET && if (GetLastError() == NTE_BAD_KEYSET &&
!CryptAcquireContext(&gCryptProv, !CryptAcquireContext(&gCryptProv,
NULL, NULL,
NULL, NULL,
PROV_RSA_FULL, PROV_RSA_FULL,
CRYPT_NEWKEYSET)) CRYPT_NEWKEYSET))
{ {
printf("CryptoLib: %x\n", unsupported_str, GetLastError()); printf("CryptoLib: %x\n", unsupported_str, GetLastError());
exit(1); exit(1);
} }
} }
#elif defined(ESP8266)
#else #else
/* start of with a stack to copy across */ /* start of with a stack to copy across */
int i; int i;
memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE); memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE);
srand((unsigned int)&i); srand((unsigned int)&i);
#endif #endif
} }
@ -161,15 +163,22 @@ EXP_FUNC void STDCALL RNG_terminate(void)
* Set a series of bytes with a random number. Individual bytes can be 0 * Set a series of bytes with a random number. Individual bytes can be 0
*/ */
EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data) EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
{ {
#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM) #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
/* use the Linux default */ /* use the Linux default */
read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */ read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */
#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB) #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
/* use Microsoft Crypto Libraries */ /* use Microsoft Crypto Libraries */
CryptGenRandom(gCryptProv, num_rand_bytes, rand_data); CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
#elif defined(ESP8266)
for (size_t cb = 0; cb < num_rand_bytes; cb += 4) {
uint32_t r = phy_get_rand();
size_t left = num_rand_bytes - cb;
left = (left < 4) ? left : 4;
memcpy(rand_data + cb, &r, left);
}
#else /* nothing else to use, so use a custom RNG */ #else /* nothing else to use, so use a custom RNG */
/* The method we use when we've got nothing better. Use RC4, time /* The method we use when we've got nothing better. Use RC4, time
and a couple of random seeds to generate a random sequence */ and a couple of random seeds to generate a random sequence */
RC4_CTX rng_ctx; RC4_CTX rng_ctx;
struct timeval tv; struct timeval tv;
@ -179,10 +188,10 @@ EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
int i; int i;
/* A proper implementation would use counters etc for entropy */ /* A proper implementation would use counters etc for entropy */
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
ep = (uint64_t *)entropy_pool; ep = (uint64_t *)entropy_pool;
ep[0] ^= ENTROPY_COUNTER1; ep[0] ^= ENTROPY_COUNTER1;
ep[1] ^= ENTROPY_COUNTER2; ep[1] ^= ENTROPY_COUNTER2;
/* use a digested version of the entropy pool as a key */ /* use a digested version of the entropy pool as a key */
MD5_Init(&rng_digest_ctx); MD5_Init(&rng_digest_ctx);
@ -214,8 +223,9 @@ void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
for (i = 0; i < num_rand_bytes; i++) for (i = 0; i < num_rand_bytes; i++)
{ {
while (rand_data[i] == 0) /* can't be 0 */ while (rand_data[i] == 0) {
rand_data[i] = (uint8_t)(rand()); get_random(1, rand_data + i);
}
} }
} }
@ -267,7 +277,7 @@ static void print_hex(uint8_t hex)
* @param data [in] The start of data to use * @param data [in] The start of data to use
* @param ... [in] Any additional arguments * @param ... [in] Any additional arguments
*/ */
EXP_FUNC void STDCALL print_blob(const char *format, EXP_FUNC void STDCALL print_blob(const char *format,
const uint8_t *data, int size, ...) const uint8_t *data, int size, ...)
{ {
int i; int i;
@ -348,7 +358,7 @@ EXP_FUNC int STDCALL base64_decode(const char *in, int len,
} }
/* check that we don't go past the output buffer */ /* check that we don't go past the output buffer */
if (z > *outlen) if (z > *outlen)
goto error; goto error;
} }
@ -368,4 +378,3 @@ error:
} }
#endif #endif