1998-04-21 02:43:54 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-04-21 02:43:54 +04:00
Functions to create reasonable random numbers for crypto use .
2001-05-24 22:24:54 +04:00
Copyright ( C ) Jeremy Allison 2001
1998-04-21 02:43:54 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2001-05-24 22:24:54 +04:00
static unsigned char hash [ 258 ] ;
static uint32 counter ;
2002-07-15 14:35:28 +04:00
static unsigned char * reseed_data ;
static size_t reseed_data_size ;
2001-05-24 22:24:54 +04:00
/****************************************************************
Copy any user given reseed data .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void set_rand_reseed_data ( unsigned char * data , size_t len )
{
2001-09-17 06:19:44 +04:00
SAFE_FREE ( reseed_data ) ;
2001-05-24 22:24:54 +04:00
reseed_data_size = 0 ;
reseed_data = ( unsigned char * ) memdup ( data , len ) ;
if ( reseed_data )
reseed_data_size = len ;
}
/****************************************************************
Setup the seed .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void seed_random_stream ( unsigned char * seedval , size_t seedlen )
{
unsigned char j = 0 ;
size_t ind ;
for ( ind = 0 ; ind < 256 ; ind + + )
hash [ ind ] = ( unsigned char ) ind ;
for ( ind = 0 ; ind < 256 ; ind + + ) {
unsigned char tc ;
j + = ( hash [ ind ] + seedval [ ind % seedlen ] ) ;
tc = hash [ ind ] ;
hash [ ind ] = hash [ j ] ;
hash [ j ] = tc ;
}
hash [ 256 ] = 0 ;
hash [ 257 ] = 0 ;
}
/****************************************************************
Get datasize bytes worth of random data .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void get_random_stream ( unsigned char * data , size_t datasize )
{
unsigned char index_i = hash [ 256 ] ;
unsigned char index_j = hash [ 257 ] ;
size_t ind ;
for ( ind = 0 ; ind < datasize ; ind + + ) {
unsigned char tc ;
unsigned char t ;
index_i + + ;
index_j + = hash [ index_i ] ;
tc = hash [ index_i ] ;
hash [ index_i ] = hash [ index_j ] ;
hash [ index_j ] = tc ;
t = hash [ index_i ] + hash [ index_j ] ;
data [ ind ] = hash [ t ] ;
}
hash [ 256 ] = index_i ;
hash [ 257 ] = index_j ;
}
1998-04-21 03:57:29 +04:00
1998-04-21 11:17:35 +04:00
/****************************************************************
2001-05-24 22:24:54 +04:00
Get a 16 byte hash from the contents of a file .
Note that the hash is not initialised .
1998-04-21 11:17:35 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-24 22:24:54 +04:00
2003-01-03 11:28:12 +03:00
static void do_filehash ( const char * fname , unsigned char * the_hash )
1998-04-21 11:17:35 +04:00
{
unsigned char buf [ 1011 ] ; /* deliberate weird size */
unsigned char tmp_md4 [ 16 ] ;
int fd , n ;
1998-11-17 23:50:07 +03:00
fd = sys_open ( fname , O_RDONLY , 0 ) ;
2001-05-24 22:24:54 +04:00
if ( fd = = - 1 )
return ;
1998-04-21 11:17:35 +04:00
while ( ( n = read ( fd , ( char * ) buf , sizeof ( buf ) ) ) > 0 ) {
mdfour ( tmp_md4 , buf , n ) ;
for ( n = 0 ; n < 16 ; n + + )
2001-05-29 11:34:51 +04:00
the_hash [ n ] ^ = tmp_md4 [ n ] ;
1998-04-21 11:17:35 +04:00
}
close ( fd ) ;
}
1998-04-21 02:43:54 +04:00
/**************************************************************
Try and get a good random number seed . Try a number of
2001-05-24 22:24:54 +04:00
different factors . Firstly , try / dev / urandom - use if exists .
1998-04-21 11:17:35 +04:00
1999-04-28 06:00:38 +04:00
We use / dev / urandom as a read of / dev / random can block if
the entropy pool dries up . This leads clients to timeout
or be very slow on connect .
2001-05-24 22:24:54 +04:00
If we can ' t use / dev / urandom then seed the stream random generator
above . . .
1998-04-21 02:43:54 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-24 22:24:54 +04:00
static int do_reseed ( BOOL use_fd , int fd )
1998-04-21 02:43:54 +04:00
{
2001-05-24 22:24:54 +04:00
unsigned char seed_inbuf [ 40 ] ;
uint32 v1 , v2 ; struct timeval tval ; pid_t mypid ;
struct passwd * pw ;
if ( use_fd ) {
if ( fd ! = - 1 )
return fd ;
fd = sys_open ( " /dev/urandom " , O_RDONLY , 0 ) ;
if ( fd > = 0 )
return fd ;
}
/* Add in some secret file contents */
do_filehash ( " /etc/shadow " , & seed_inbuf [ 0 ] ) ;
do_filehash ( lp_smb_passwd_file ( ) , & seed_inbuf [ 16 ] ) ;
/*
* Add in the root encrypted password .
* On any system where security is taken
* seriously this will be secret .
*/
2002-01-23 15:59:24 +03:00
pw = getpwnam_alloc ( " root " ) ;
2001-05-24 22:24:54 +04:00
if ( pw & & pw - > pw_passwd ) {
size_t i ;
unsigned char md4_tmp [ 16 ] ;
mdfour ( md4_tmp , ( unsigned char * ) pw - > pw_passwd , strlen ( pw - > pw_passwd ) ) ;
for ( i = 0 ; i < 16 ; i + + )
seed_inbuf [ 8 + i ] ^ = md4_tmp [ i ] ;
2002-01-23 15:59:24 +03:00
passwd_free ( & pw ) ;
2001-05-24 22:24:54 +04:00
}
/*
* Add the counter , time of day , and pid .
*/
GetTimeOfDay ( & tval ) ;
mypid = sys_getpid ( ) ;
v1 = ( counter + + ) + mypid + tval . tv_sec ;
v2 = ( counter + + ) * mypid + tval . tv_usec ;
SIVAL ( seed_inbuf , 32 , v1 ^ IVAL ( seed_inbuf , 32 ) ) ;
SIVAL ( seed_inbuf , 36 , v2 ^ IVAL ( seed_inbuf , 36 ) ) ;
/*
* Add any user - given reseed data .
*/
if ( reseed_data ) {
size_t i ;
for ( i = 0 ; i < sizeof ( seed_inbuf ) ; i + + )
seed_inbuf [ i ] ^ = reseed_data [ i % reseed_data_size ] ;
}
seed_random_stream ( seed_inbuf , sizeof ( seed_inbuf ) ) ;
return - 1 ;
1998-04-21 02:43:54 +04:00
}
/*******************************************************************
Interface to the ( hopefully ) good crypto random number generator .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-24 22:24:54 +04:00
void generate_random_buffer ( unsigned char * out , int len , BOOL do_reseed_now )
1998-04-21 02:43:54 +04:00
{
2001-05-24 22:24:54 +04:00
static BOOL done_reseed = False ;
static int urand_fd = - 1 ;
unsigned char md4_buf [ 64 ] ;
unsigned char tmp_buf [ 16 ] ;
unsigned char * p ;
if ( ! done_reseed | | do_reseed_now ) {
urand_fd = do_reseed ( True , urand_fd ) ;
done_reseed = True ;
}
if ( urand_fd ! = - 1 & & len > 0 ) {
if ( read ( urand_fd , out , len ) = = len )
return ; /* len bytes of random data read from urandom. */
/* Read of urand error, drop back to non urand method. */
close ( urand_fd ) ;
urand_fd = - 1 ;
do_reseed ( False , - 1 ) ;
done_reseed = True ;
}
/*
* Generate random numbers in chunks of 64 bytes ,
* then md4 them & copy to the output buffer .
* This way the raw state of the stream is never externally
* seen .
*/
p = out ;
while ( len > 0 ) {
int copy_len = len > 16 ? 16 : len ;
get_random_stream ( md4_buf , sizeof ( md4_buf ) ) ;
mdfour ( tmp_buf , md4_buf , sizeof ( md4_buf ) ) ;
memcpy ( p , tmp_buf , copy_len ) ;
p + = copy_len ;
len - = copy_len ;
}
1998-04-21 02:43:54 +04:00
}
2001-04-12 11:00:08 +04:00
/*******************************************************************
Use the random number generator to generate a random string .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-04-12 11:20:15 +04:00
static char c_list [ ] = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#., " ;
2001-04-12 11:00:08 +04:00
char * generate_random_str ( size_t len )
{
static unsigned char retstr [ 256 ] ;
size_t i ;
memset ( retstr , ' \0 ' , sizeof ( retstr ) ) ;
if ( len > sizeof ( retstr ) - 1 )
len = sizeof ( retstr ) - 1 ;
generate_random_buffer ( retstr , len , False ) ;
for ( i = 0 ; i < len ; i + + )
2002-08-17 21:00:51 +04:00
retstr [ i ] = c_list [ retstr [ i ] % ( sizeof ( c_list ) - 1 ) ] ;
2001-04-12 11:00:08 +04:00
retstr [ i ] = ' \0 ' ;
2001-04-13 23:12:06 +04:00
return ( char * ) retstr ;
2001-04-12 11:00:08 +04:00
}