mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-02-21 17:13:22 +00:00
237 lines
5.8 KiB
C
237 lines
5.8 KiB
C
/*
|
|
* Cross Platform random/uuid abstraction
|
|
* Copyright(C) 2015 Michael Jerris
|
|
*
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
* furnished to do so.
|
|
*
|
|
* This work is provided under this license on an "as is" basis, without warranty of any kind,
|
|
* either expressed or implied, including, without limitation, warranties that the covered code
|
|
* is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire
|
|
* risk as to the quality and performance of the covered code is with you. Should any covered
|
|
* code prove defective in any respect, you (not the initial developer or any other contributor)
|
|
* assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty
|
|
* constitutes an essential part of this license. No use of any covered code is authorized hereunder
|
|
* except under this disclaimer.
|
|
*
|
|
*/
|
|
|
|
#include "ks.h"
|
|
#include <aes.h>
|
|
#include <sha2.h>
|
|
|
|
static ks_bool_t initialized = KS_FALSE;
|
|
static ks_mutex_t *rng_mutex = NULL;
|
|
static sha512_ctx global_sha512;
|
|
|
|
#ifdef __WINDOWS__
|
|
#include <Wincrypt.h>
|
|
HCRYPTPROV crypt_provider;
|
|
#else
|
|
int fd = -1;
|
|
#endif
|
|
|
|
/*
|
|
* memset_volatile is a volatile pointer to the memset function.
|
|
* You can call (*memset_volatile)(buf, val, len) or even
|
|
* memset_volatile(buf, val, len) just as you would call
|
|
* memset(buf, val, len), but the use of a volatile pointer
|
|
* guarantees that the compiler will not optimise the call away.
|
|
*/
|
|
static void * (*volatile memset_volatile)(void *, int, size_t) = memset;
|
|
|
|
KS_DECLARE(uuid_t *) ks_uuid(uuid_t *uuid)
|
|
{
|
|
#ifdef __WINDOWS__
|
|
UuidCreate ( uuid );
|
|
#else
|
|
uuid_generate_random ( *uuid );
|
|
#endif
|
|
return uuid;
|
|
}
|
|
|
|
KS_DECLARE(char *) ks_uuid_str(ks_pool_t *pool, uuid_t *uuid)
|
|
{
|
|
char *uuidstr = ks_pool_alloc(pool, 37);
|
|
#ifdef __WINDOWS__
|
|
unsigned char * str;
|
|
UuidToStringA ( uuid, &str );
|
|
uuidstr = ks_pstrdup(pool, (const char *)str);
|
|
RpcStringFreeA ( &str );
|
|
#else
|
|
char str[37] = { 0 };
|
|
uuid_unparse ( *uuid, str );
|
|
uuidstr = ks_pstrdup(pool, str);
|
|
#endif
|
|
return uuidstr;
|
|
}
|
|
|
|
KS_DECLARE(ks_status_t) ks_rng_init(void)
|
|
{
|
|
if (!initialized) {
|
|
|
|
|
|
ks_aes_init();
|
|
ks_mutex_create(&rng_mutex, KS_MUTEX_FLAG_DEFAULT, ks_global_pool());
|
|
#ifdef __WINDOWS__
|
|
if (!crypt_provider) {
|
|
if (CryptAcquireContext(&crypt_provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == TRUE) {
|
|
initialized = KS_TRUE;
|
|
} else {
|
|
initialized = KS_FALSE;
|
|
}
|
|
}
|
|
#else
|
|
if (fd < 0) {
|
|
fd = open("/dev/urandom", O_RDONLY);
|
|
if (fd < 0) {
|
|
fd = open("/dev/random", O_RDONLY);
|
|
}
|
|
}
|
|
initialized = KS_TRUE;
|
|
#endif
|
|
}
|
|
|
|
sha512_begin(&global_sha512);
|
|
|
|
if (initialized) {
|
|
return KS_STATUS_SUCCESS;
|
|
} else {
|
|
return KS_STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
KS_DECLARE(ks_status_t) ks_rng_shutdown(void)
|
|
{
|
|
|
|
initialized = KS_FALSE;
|
|
#ifdef __WINDOWS__
|
|
if (crypt_provider) {
|
|
CryptReleaseContext(crypt_provider, 0);
|
|
crypt_provider = 0;
|
|
}
|
|
#else
|
|
if (fd >= 0) {
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
#endif
|
|
return KS_STATUS_SUCCESS;
|
|
}
|
|
|
|
KS_DECLARE(size_t) ks_rng_seed_data(uint8_t *seed, size_t length)
|
|
{
|
|
size_t bytes = 0;
|
|
|
|
if (!initialized && (ks_rng_init() != KS_STATUS_SUCCESS)) {
|
|
return bytes;
|
|
}
|
|
#ifdef __WINDOWS__
|
|
if (crypt_provider) {
|
|
if(!CryptGenRandom(crypt_provider, (DWORD)length, seed)) {
|
|
return 0;
|
|
}
|
|
bytes = length;
|
|
}
|
|
#else
|
|
if (fd >= 0) {
|
|
bytes = read(fd, seed, length);
|
|
} else {
|
|
}
|
|
#endif
|
|
return bytes;
|
|
}
|
|
|
|
KS_DECLARE(size_t) ks_rng_add_entropy(const uint8_t *buffer, size_t length)
|
|
{
|
|
|
|
uint8_t seed[64];
|
|
size_t len = ks_rng_seed_data(seed, sizeof(seed));
|
|
|
|
ks_mutex_lock(rng_mutex);
|
|
|
|
if (!initialized) {
|
|
ks_rng_init();
|
|
}
|
|
|
|
if (buffer && length) {
|
|
sha512_hash(buffer, (unsigned long)length, &global_sha512);
|
|
}
|
|
|
|
if (len > 0) {
|
|
sha512_hash(seed, (unsigned long)len, &global_sha512);
|
|
length += len;
|
|
}
|
|
|
|
ks_mutex_unlock(rng_mutex);
|
|
|
|
return length;
|
|
}
|
|
|
|
KS_DECLARE(size_t) ks_rng_get_data(uint8_t* buffer, size_t length) {
|
|
|
|
aes_encrypt_ctx cx[1];
|
|
sha512_ctx random_context;
|
|
uint8_t md[SHA512_DIGEST_SIZE];
|
|
uint8_t ctr[AES_BLOCK_SIZE];
|
|
uint8_t rdata[AES_BLOCK_SIZE];
|
|
size_t generated = length;
|
|
|
|
/* Add entropy from system state. We will include whatever happens to be in the buffer, it can't hurt */
|
|
ks_rng_add_entropy(buffer, length);
|
|
|
|
ks_mutex_lock(rng_mutex);
|
|
|
|
/* Copy the mainCtx and finalize it into the md buffer */
|
|
memcpy(&random_context, &global_sha512, sizeof(sha512_ctx));
|
|
sha512_end(md, &random_context);
|
|
|
|
ks_mutex_lock(rng_mutex);
|
|
|
|
/* Key an AES context from this buffer */
|
|
aes_encrypt_key256(md, cx);
|
|
|
|
/* Initialize counter, using excess from md if available */
|
|
memset (ctr, 0, sizeof(ctr));
|
|
uint32_t ctrbytes = AES_BLOCK_SIZE;
|
|
memcpy(ctr + sizeof(ctr) - ctrbytes, md + 32, ctrbytes);
|
|
|
|
/* Encrypt counter, copy to destination buffer, increment counter */
|
|
while (length) {
|
|
uint8_t *ctrptr;
|
|
size_t copied;
|
|
aes_encrypt(ctr, rdata, cx);
|
|
copied = (sizeof(rdata) < length) ? sizeof(rdata) : length;
|
|
memcpy (buffer, rdata, copied);
|
|
buffer += copied;
|
|
length -= copied;
|
|
|
|
/* Increment counter */
|
|
ctrptr = ctr + sizeof(ctr) - 1;
|
|
while (ctrptr >= ctr) {
|
|
if ((*ctrptr-- += 1) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
memset_volatile(&random_context, 0, sizeof(random_context));
|
|
memset_volatile(md, 0, sizeof(md));
|
|
memset_volatile(&cx, 0, sizeof(cx));
|
|
memset_volatile(ctr, 0, sizeof(ctr));
|
|
memset_volatile(rdata, 0, sizeof(rdata));
|
|
|
|
return generated;
|
|
}
|
|
|
|
/* For Emacs:
|
|
* Local Variables:
|
|
* mode:c
|
|
* indent-tabs-mode:t
|
|
* tab-width:4
|
|
* c-basic-offset:4
|
|
* End:
|
|
* For VIM:
|
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
|
*/
|