mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-22 11:14:13 +00:00
Thanks to Phil Zimmermann for the code and for the license exception we needed to include it. There remains some build system integration work to be done before this code will build properly in the FreeSWITCH tree.
346 lines
9.6 KiB
C
346 lines
9.6 KiB
C
/*
|
|
* libZRTP SDK library, implements the ZRTP secure VoIP protocol.
|
|
* Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved.
|
|
* Contact: http://philzimmermann.com
|
|
* For licensing and other legal details, see the file zrtp_legal.c.
|
|
*/
|
|
|
|
#include "zrtp.h"
|
|
|
|
#define _ZTU_ "zrtp rng"
|
|
|
|
#define MD_DIGEST_LENGTH SHA512_DIGEST_SIZE
|
|
#define MD_CTX_init(a)
|
|
#define MD_Init(a) sha512_begin(a)
|
|
#define MD_Final(a,b) sha512_end(b,a)
|
|
#define MD_Cleanup(a) zrtp_memset(a,0,sizeof(*a));
|
|
|
|
|
|
#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE)
|
|
|
|
#include <Wincrypt.h>
|
|
|
|
HCRYPTPROV g_hCryptProv;
|
|
|
|
zrtp_status_t NtLmInitializeRNG(VOID)
|
|
{
|
|
BOOL fSuccess;
|
|
|
|
if (g_hCryptProv != 0) {
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
fSuccess = CryptAcquireContext( &g_hCryptProv,
|
|
NULL,
|
|
NULL,
|
|
PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT);
|
|
|
|
return (TRUE == fSuccess) ? zrtp_status_ok : zrtp_status_fail;
|
|
}
|
|
|
|
void NtLmCleanupRNG(VOID)
|
|
{
|
|
if (g_hCryptProv) {
|
|
CryptReleaseContext(g_hCryptProv, 0);
|
|
g_hCryptProv = 0;
|
|
}
|
|
}
|
|
|
|
int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx)
|
|
{
|
|
uint8_t buffer[64];
|
|
|
|
if(!CryptGenRandom(g_hCryptProv, sizeof(buffer), buffer)) {
|
|
ZRTP_LOG(1,(_ZTU_,"\tERROR! Error during CryptGenRandom.\n"));
|
|
return 0;
|
|
}
|
|
|
|
MD_Update(ctx, buffer, sizeof(buffer));
|
|
ZeroMemory((PVOID)buffer, sizeof(buffer));
|
|
|
|
return sizeof(buffer);
|
|
}
|
|
|
|
#elif (ZRTP_PLATFORM == ZP_WIN32_KERNEL)
|
|
|
|
#include <Ndis.h>
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx)
|
|
{
|
|
LARGE_INTEGER li1;
|
|
LARGE_INTEGER li2;
|
|
ULONG ul1;
|
|
ULONG ul2;
|
|
ULONGLONG ull;
|
|
PKTHREAD thread;
|
|
static int tsc_ok = 1;
|
|
/*
|
|
* WARNING!
|
|
* Of course it's not a real size of entropy added to the context. It's very
|
|
* difficult to compute the size of real random data and estimate its quality.
|
|
* This value means: size of maximum possible random data which this function can provide.
|
|
*/
|
|
static int entropy_length = sizeof(LARGE_INTEGER)*2 + sizeof(PKTHREAD) +
|
|
sizeof(ULONG)*2 + sizeof(LARGE_INTEGER)*2 + sizeof(ULONG)*2;
|
|
|
|
li2 = KeQueryPerformanceCounter(&li1);
|
|
MD_Update(ctx, &li1, sizeof(LARGE_INTEGER));
|
|
MD_Update(ctx, &li2, sizeof(LARGE_INTEGER));
|
|
|
|
ull = KeQueryInterruptTime();
|
|
MD_Update(ctx, &ull, sizeof(ULONGLONG));
|
|
|
|
thread = KeGetCurrentThread();
|
|
MD_Update(ctx, &thread, sizeof(PKTHREAD));
|
|
ul2 = KeQueryRuntimeThread(thread, &ul1);
|
|
MD_Update(ctx, &ul1, sizeof(ULONG));
|
|
MD_Update(ctx, &ul2, sizeof(ULONG));
|
|
|
|
KeQuerySystemTime(&li1);
|
|
MD_Update(ctx, &li1, sizeof(LARGE_INTEGER));
|
|
|
|
KeQueryTickCount(&li1);
|
|
MD_Update(ctx, &li1, sizeof(LARGE_INTEGER));
|
|
|
|
if (tsc_ok) {
|
|
__try {
|
|
ull = _RDTSC();
|
|
MD_Update(ctx, &ull, sizeof(ULONGLONG));
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
tsc_ok = 0;
|
|
}
|
|
}
|
|
|
|
return entropy_length;
|
|
}
|
|
|
|
#elif ((ZRTP_PLATFORM == ZP_SYMBIAN))
|
|
/*
|
|
* WARNING!
|
|
* This is just a stub to let you start with something little bit better then zero.
|
|
* We have no possibility to implement entropy collection in this abstract cross-platform
|
|
* application. This function MUST NOT be used as example in real applications. For more
|
|
* information read \ref RNG in developers guide
|
|
*
|
|
* To add real entropy - capture random data from microphone and camera.
|
|
*/
|
|
extern uint32_t zrtp_symbian_kernel_random();
|
|
extern uint32_t zrtp_sum_of_pid_and_number_of_poccesses();
|
|
extern uint64_t zrtp_get_system_time_crazy();
|
|
extern unsigned int zrtp_get_pid();
|
|
extern uint32_t zrtp_get_availible_heap();
|
|
|
|
|
|
int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx) {
|
|
uint64_t sysdate;
|
|
unsigned int pid;
|
|
uint32_t crazy_pid_sum;
|
|
|
|
uint32_t heap_size;
|
|
|
|
static int entropy_length = sizeof(sysdate) + sizeof(pid)
|
|
+ sizeof(crazy_pid_sum) + sizeof(heap_size);
|
|
sysdate = zrtp_get_system_time_crazy();
|
|
MD_Update(ctx,&sysdate,sizeof(sysdate));
|
|
|
|
pid = zrtp_get_pid();
|
|
|
|
MD_Update(ctx,&pid,sizeof(pid));
|
|
|
|
crazy_pid_sum = zrtp_sum_of_pid_and_number_of_poccesses();
|
|
MD_Update(ctx,&crazy_pid_sum,sizeof(crazy_pid_sum));
|
|
|
|
heap_size = zrtp_get_availible_heap();
|
|
MD_Update(ctx,&heap_size,sizeof(heap_size));
|
|
|
|
return entropy_length;
|
|
}
|
|
|
|
#elif ( (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) || (ZRTP_PLATFORM == ZP_ANDROID) )
|
|
|
|
#if ZRTP_HAVE_STDIO_H == 1
|
|
# include <stdio.h>
|
|
#else
|
|
# error "Used environment dosn't have <stdio.h> - zrtp_rng.c can't be build."
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx)
|
|
{
|
|
uint8_t buffer[64];
|
|
size_t bytes_read = 0;
|
|
static size_t length= sizeof(buffer);
|
|
FILE *fp = NULL;
|
|
|
|
fp = fopen("/dev/urandom", "rb");
|
|
if (!fp) {
|
|
ZRTP_LOG(1,(_ZTU_,"\tERROR! can't get access to /dev/urandom - trying /dev/random.\n"));
|
|
fp = fopen("/dev/random", "rb");
|
|
}
|
|
|
|
if (fp) {
|
|
int number_of_retries = 1024;
|
|
while ((bytes_read < length) && (number_of_retries-- > 0)) {
|
|
setbuf(fp, NULL); /* Otherwise fread() tries to read() 4096 bytes or other default value */
|
|
bytes_read += fread(buffer+bytes_read, 1, length-bytes_read, fp);
|
|
}
|
|
|
|
if (0 != fclose(fp)) {
|
|
ZRTP_LOG(1,(_ZTU_,"\tERROR! unable to cloas /dev/random\n"));
|
|
}
|
|
} else {
|
|
ZRTP_LOG(1,(_ZTU_,"\tERROR! RNG Can't open /dev/random\n"));
|
|
}
|
|
|
|
if (bytes_read < length) {
|
|
ZRTP_LOG(1,(_ZTU_,"\tERROR! can't read random string! Current session have to be closed.\n"));
|
|
return -1;
|
|
}
|
|
|
|
MD_Update(ctx, buffer, length);
|
|
zrtp_memset(buffer, 0, sizeof(buffer));
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
zrtp_status_t zrtp_init_rng(zrtp_global_t* zrtp)
|
|
{
|
|
if (!zrtp->rand_initialized) {
|
|
zrtp_mutex_init(&zrtp->rng_protector);
|
|
MD_Init(&zrtp->rand_ctx);
|
|
#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE)
|
|
if (zrtp_status_ok != NtLmInitializeRNG()) {
|
|
ZRTP_LOG(1,(_ZTU_,"\tERROR! during CryptAcquireContext!\n"));
|
|
return zrtp_status_fail;
|
|
}
|
|
#endif
|
|
zrtp->rand_initialized = 1;
|
|
}
|
|
|
|
return zrtp_status_ok;
|
|
}
|
|
|
|
void zrtp_down_rng(zrtp_global_t* zrtp)
|
|
{
|
|
if (zrtp->rand_initialized) {
|
|
zrtp_mutex_destroy(zrtp->rng_protector);
|
|
#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE)
|
|
NtLmCleanupRNG();
|
|
#endif
|
|
zrtp->rand_initialized = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Call this to add entropy to the system from the given buffer,
|
|
* and also from the system state. It's OK to pass a null buffer
|
|
* with a length of zero, then we will just use the system entropy.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int zrtp_entropy_add(zrtp_global_t* zrtp, const unsigned char *buffer, uint32_t length)
|
|
{
|
|
if (buffer && length) {
|
|
MD_Update(&zrtp->rand_ctx, buffer, length);
|
|
}
|
|
|
|
return zrtp_add_system_state(zrtp, &zrtp->rand_ctx);
|
|
}
|
|
|
|
|
|
/*
|
|
* Random bits are produced as follows.
|
|
* First stir new entropy into the random state (zrtp->rand_ctx).
|
|
* Then make a copy of the random context and finalize it.
|
|
* Use the digest to seed an AES-256 context and, if space remains, to
|
|
* initialize a counter.
|
|
* Then encrypt the counter with the AES-256 context, incrementing it
|
|
* per block, until we have produced the desired quantity of data.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int zrtp_randstr(zrtp_global_t* zrtp, unsigned char *buffer, uint32_t length)
|
|
{
|
|
//TODO: replace bg_aes_xxx() with our own block cipher component.
|
|
//TODO: Do the same with the hash functions.
|
|
|
|
aes_encrypt_ctx aes_ctx;
|
|
MD_CTX rand_ctx2;
|
|
unsigned char md[MD_DIGEST_LENGTH];
|
|
unsigned char ctr[AES_BLOCK_SIZE];
|
|
unsigned char rdata[AES_BLOCK_SIZE];
|
|
uint32_t generated = length;
|
|
|
|
/*
|
|
* In few cases we need to gerate random value before initializing libzrtp engine.
|
|
* Following trick makes it possible.
|
|
*/
|
|
if (!zrtp->rand_initialized) {
|
|
if (zrtp_status_ok != zrtp_init_rng(zrtp)) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
zrtp_mutex_lock(zrtp->rng_protector);
|
|
|
|
/*
|
|
* Add entropy from system state
|
|
* We will include whatever happens to be in the buffer, it can't hurt
|
|
*/
|
|
if ( 0 > zrtp_entropy_add(zrtp, buffer, length) ) {
|
|
zrtp_mutex_unlock(zrtp->rng_protector);
|
|
return -1;
|
|
}
|
|
|
|
/* Copy the zrtp->rand_ctx and finalize it into the md buffer */
|
|
rand_ctx2 = zrtp->rand_ctx;
|
|
MD_Final(&rand_ctx2, md);
|
|
|
|
zrtp_mutex_unlock(zrtp->rng_protector);
|
|
|
|
/* Key an AES context from this buffer */
|
|
zrtp_bg_aes_encrypt_key256(md, &aes_ctx);
|
|
|
|
/* Initialize counter, using excess from md if available */
|
|
zrtp_memset (ctr, 0, sizeof(ctr));
|
|
if (MD_DIGEST_LENGTH > (256/8)) {
|
|
uint32_t ctrbytes = MD_DIGEST_LENGTH - (256/8);
|
|
if (ctrbytes > AES_BLOCK_SIZE)
|
|
ctrbytes = AES_BLOCK_SIZE;
|
|
zrtp_memcpy(ctr + sizeof(ctr) - ctrbytes, md + (256/8), ctrbytes);
|
|
}
|
|
|
|
/* Encrypt counter, copy to destination buffer, increment counter */
|
|
while (length)
|
|
{
|
|
unsigned char *ctrptr;
|
|
uint32_t copied;
|
|
zrtp_bg_aes_encrypt(ctr, rdata, &aes_ctx);
|
|
copied = (sizeof(rdata) < length) ? sizeof(rdata) : length;
|
|
zrtp_memcpy (buffer, rdata, copied);
|
|
buffer += copied;
|
|
length -= copied;
|
|
|
|
/* Increment counter */
|
|
ctrptr = ctr + sizeof(ctr) - 1;
|
|
while (ctrptr >= ctr) {
|
|
if ((*ctrptr-- += 1) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Done! Cleanup and exit */
|
|
MD_Cleanup (&rand_ctx2);
|
|
MD_Cleanup (md);
|
|
MD_Cleanup (&aes_ctx);
|
|
MD_Cleanup (ctr);
|
|
MD_Cleanup (rdata);
|
|
|
|
return generated;
|
|
}
|