/* dot11RandLib.c - random number generator for wireless framework */ /* Modification History -------------------- 02a,02mar10,kr Initial version */ /* DESCRIPTION This module contains functions for generating random numbers: - depends on openssl for the SHA256 and MD5 hashes; - code adapted from the CCI library (cci_DefaultRand.c). \NOMANUAL */ #include #include #include #include #include "drv/wlan/dot11Lib.h" #include "drv/wlan/dot11RsnLib.h" /**************************************************************************** * * *** Restricted Rights Legend *** * * The programs and information contained herein are licensed only * pursuant to a license agreement that contains use, reverse * engineering, disclosure, and other restrictions; accordingly, it * is "Unpublished--all rights reserved under the applicable * copyright laws". * * Use duplication, or disclosure by the Government is subject to * restrictions as set forth in subparagraph (c)(1)(ii) of the Rights * in Technical Data and Computer Licensed Programs clause of DFARS * 52.227 7013. * * Copyright 2000-2010 Wind River Systems, Inc. * Copyright 1997 Epilogue Technology Corporation. * Copyright 1998-1999 Integrated Systems, Inc. * All rights reserved. * * *** Government Use *** * * The Licensed Programs and their documentation were developed at * private expense and no part of them is in the public domain. * * The Licensed Programs are "Restricted Computer Software" as that * term is defined in Clause 52.227-19 of the Federal Acquisition * Regulations (FAR) and are "Commercial Computer Software" as that * term is defined in Subpart 227.401 of the Department of Defense * Federal Acquisition Regulation Supplement (DFARS). * * (i) If the licensed Programs are supplied to the Department of * Defense (DoD), the Licensed Programs are classified as * "Commercial Computer Software" and the Government is acquiring * only "restricted rights" in the Licensed Programs and their * documentation as that term is defined in Clause 52.227 * 7013(c)(1) of the DFARS, and * * (ii) If the Licensed Programs are supplied to any unit or agency * of the United States Government other than DoD, the * Government's rights in the Licensed Programs and their * documentation will be as defined in Clause 52.227-19(c)(2) of * the FAR. ****************************************************************************/ /* * This file implements a cryptographically strong random number generator. * The algorithm is based on the ANSI X9.17 generator. Keyed MD5 is used * as the basic transform rather than TDES. The DT value is augmented with * a monotonically increasing counter. See [Stallings - Network and * Internetwork Security pp 102-103] or ANSI X9.17 Appendix C. */ /* * these next 2 bits of magic are used to seed the generator with * less than 32 bytes of randomness. If the user hands in N < 32 bytes (call * them "B") we generate MD5 (MAGIC1 "+" B "+" MAGIC1), and * MD5 (MAGIC2 "+" B "+" MAGIC2), and combine them to get our needed 32 bytes. * The actual values here are *not* of any importance, although having a * reasonably "random" bit distribution is useful. These were generated by * running some real-time system statistics through MD5. */ static UINT8 PRNG_MAGIC1 [] = { 0xb4, 0x33, 0x4b, 0xf5, 0x9b, 0x7a, 0x24, 0x19, 0x8c, 0x04, 0xa5, 0xd1, 0x1e, 0xab, 0xa2, 0xe9 }; static UINT8 PRNG_MAGIC2 [] = { 0xaa, 0x9b, 0x49, 0xd4, 0x0f, 0x4c, 0xa7, 0x1b, 0x1d, 0x0e, 0x83, 0xd6, 0xe7, 0x9c, 0xab, 0xf8 }; #define PRNG_SEEDBYTES_NEEDED 32 static MD5_CTX PRNG_CCI_MD5_CONTEXT; static UINT8 PRNG_MD5_K[16]; /* MD5 keyed hash key */ static UINT8 PRNG_SV[16]; /* current seed value */ static UINT8 PRNG_R[16]; /* current random pool */ static UINT32 PRNG_DT; /* "date+time" value */ static UINT32 PRNG_CNT; /* counter; increments with each call */ static UINT8 PRNG_N; /* number of "random" bytes currently available */ static UINT8 PRNG_INJIDX; /* index of PRNG_SV where prng_inject_random8 will xor next random input into */ static SEM_ID defaultMtx; /* ** --- randomly get current time */ static UINT32 randomTime( void ) { struct timespec tspec; clock_gettime( CLOCK_REALTIME, &tspec ); return( (UINT32) tspec.tv_nsec ); } /* ** --- Get a random number from the SHA256 algorithm that produces ** a 32-byte digest --- which is equal to PRNG_SEEDBYTES_NEEDED(the value of the variable 'length'). */ static unsigned glue_seed_prng( UINT8 *buffer, unsigned length ) { SHA256_CTX context; UINT32 t = randomTime(); SHA256_Init( &context ); SHA256_Update( &context, (void *) &t, sizeof(UINT32) ); SHA256_Final( buffer, &context ); return( length ); } /* * compute next seed value and state */ static void prng_iterate( void ) { int i; UINT8 *p, *q; UINT8 digest[16]; /* step 1. R = MD5_K (MD5_K ((DT concat (++CNT)) XOR SV)) */ /* digest <-- MD5 ((DT concat (++CNT)) XOR SV */ ++PRNG_CNT; PRNG_DT = randomTime(); MD5_Init( &PRNG_CCI_MD5_CONTEXT ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MD5_K, 16 ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, (UINT8 *) &PRNG_DT, 4 ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, (UINT8 *) &PRNG_CNT, 4 ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MD5_K, 16 ); MD5_Final( digest, &PRNG_CCI_MD5_CONTEXT ); /* PRNG_SV <-- (PRNG_SV XOR digest) */ /* leave digest alone as we'll need it again when we compute new SV */ for( i = 0, p = PRNG_SV, q = digest; i < 16; i++ ) *p++ ^= *q++; /* PRNG_R <-- MD5 (PRNG_SV) */ MD5_Init( &PRNG_CCI_MD5_CONTEXT ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MD5_K, 16 ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_SV, 16 ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MD5_K, 16 ); MD5_Final( PRNG_R, &PRNG_CCI_MD5_CONTEXT ); /* * step 2. SV = MD5_K (MD5_K ((DT concat (++CNT)) XOR R)) * * digest is still MD5_K ((DT concat (++CNT)), so we dont need another * MD5 operation */ /* PRNG_SV <-- (PRNG_SV XOR digest) */ for( i = 0, p = PRNG_R, q = digest; i < 16; i++ ) *q++ ^= *p++; MD5_Init( &PRNG_CCI_MD5_CONTEXT ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MD5_K, 16 ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, (UINT8 *)digest, 16 ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MD5_K, 16 ); MD5_Final( PRNG_SV, &PRNG_CCI_MD5_CONTEXT ); /* now we have another 16 bytes of usable R */ PRNG_N = 16; } /* * seed the prng */ static void prng_seed( UINT32 seedSize, UINT8 *seedvalues ) { if( seedSize <= PRNG_SEEDBYTES_NEEDED ) { MD5_Init( &PRNG_CCI_MD5_CONTEXT ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MAGIC1, 16 ); if( seedSize > 0 ) MD5_Update( &PRNG_CCI_MD5_CONTEXT, seedvalues, seedSize ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MAGIC1, 16 ); MD5_Final( PRNG_MD5_K, &PRNG_CCI_MD5_CONTEXT ); MD5_Init( &PRNG_CCI_MD5_CONTEXT ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MAGIC2, 16 ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, seedvalues, seedSize ); MD5_Update( &PRNG_CCI_MD5_CONTEXT, PRNG_MAGIC2, 16 ); MD5_Final( PRNG_SV, &PRNG_CCI_MD5_CONTEXT ); memcpy( &PRNG_CNT, seedvalues, 4 ); } else { memcpy( PRNG_SV, seedvalues, 16 ); memcpy( PRNG_MD5_K, seedvalues + 16, 16 ); memcpy( &PRNG_CNT, seedvalues, 4 ); } PRNG_DT = randomTime(); PRNG_N = PRNG_INJIDX = 0; prng_iterate(); /* kick start the PRNG */ } /* * Initialize the prng system. This involves calling out for seed bytes. 32 * of them, in fact. */ static void prng_init( void ) { UINT8 seedvalues[PRNG_SEEDBYTES_NEEDED]; unsigned int seedSize; memset( seedvalues, 0, PRNG_SEEDBYTES_NEEDED ); seedSize = glue_seed_prng( seedvalues, PRNG_SEEDBYTES_NEEDED ); prng_seed( seedSize, seedvalues ); } /* * hand back a "random" byte */ static UINT8 prng_random8( void ) { if( !PRNG_N ) prng_iterate(); return PRNG_R[--PRNG_N]; } /* * fill up a buffer with "random" bytes */ static void prng_random( UINT8 *buf, UINT32 N ) { while( N-- ) *buf++ = prng_random8(); } /************************************************************************************************* * Method Name: dot11RandNum * Description: Fill buffer with random numbers. * * Parameters: * * < *buffer > - * < byteCount > - * * Returns: void - No value returned. * **************************************************************************************************/ void dot11RandNum(UINT8 *buffer, UINT32 byteCount) { semTake(defaultMtx, WAIT_FOREVER); prng_random( buffer, byteCount ); semGive(defaultMtx); } /************************************************************************************************* * Method Name: dot11RandNumInit * Description: Initialize the dot11RandLib * **************************************************************************************************/ void dot11RandNumInit(void) { defaultMtx = semBCreate(SEM_Q_FIFO, SEM_FULL); prng_init(); }