2 Unix SMB/Netbios implementation.
5 Functions to create reasonable random numbers for crypto use.
7 Copyright (C) Jeremy Allison 1998
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern int DEBUGLEVEL;
27 static uint32 counter = 0;
29 /****************************************************************
30 Try and get a seed by looking at the atimes of files in a given
31 directory. XOR them into the buf array.
32 *****************************************************************/
34 static void do_dirrand(char *name, unsigned char *buf, int buf_len)
36 void *dp = sys_opendir(name);
42 pstrcpy(fullname, name);
43 fullname_len = strlen(fullname);
45 if(fullname_len + 2 > sizeof(pstring))
48 if(fullname[fullname_len] != '/') {
49 fullname[fullname_len] = '/';
50 fullname[fullname_len+1] = '\0';
51 fullname_len = strlen(fullname);
54 len_left = sizeof(pstring) - fullname_len - 1;
55 pos = &fullname[fullname_len];
60 while ((p = readdirname(dp))) {
63 if(strlen(p) <= len_left)
66 if(sys_stat(fullname,&st) == 0) {
67 SIVAL(buf, ((counter * 4)%(buf_len-4)),
68 IVAL(buf,((counter * 4)%(buf_len-4))) ^ st.st_atime);
70 DEBUG(10,("do_dirrand: value from file %s.\n", fullname));
77 /**************************************************************
78 Try and get a good random number seed. Try a number of
79 different factors. Firstly, try /dev/random and try and
80 read from this. If this fails iterate through /tmp and
81 XOR all the file timestamps. If this fails then just use
82 a combination of pid and time of day (yes I know this
83 sucks :-). Finally md4 the result.
84 **************************************************************/
86 static uint32 do_reseed(void)
88 unsigned char md4_outbuf[16];
89 unsigned char md4_inbuf[40];
90 BOOL got_random = False;
96 memset(md4_inbuf, '\0', sizeof(md4_inbuf));
98 fd = open( "/dev/random", O_RDONLY);
101 * We can use /dev/random !
103 if(read(fd, md4_inbuf, 40) == 40) {
105 DEBUG(10,("do_reseed: got 40 bytes from /dev/random.\n"));
112 * /dev/random failed - try /tmp/ for timestamps.
114 do_dirrand("/tmp", md4_inbuf, sizeof(md4_inbuf));
115 do_dirrand("/dev", md4_inbuf, sizeof(md4_inbuf));
119 * Finally add the counter, time of day, and pid.
123 v1 = (counter++) + mypid + tval.tv_sec;
124 v2 = (counter++) * mypid + tval.tv_usec;
126 SIVAL(md4_inbuf, 32, v1 ^ IVAL(md4_inbuf, 32));
127 SIVAL(md4_inbuf, 36, v1 ^ IVAL(md4_inbuf, 36));
129 mdfour(md4_outbuf, md4_inbuf, sizeof(md4_inbuf));
131 /* XOR everything togther in blocks of 4 bytes. */
132 ret = IVAL(md4_outbuf,0);
133 ret ^= IVAL(md4_outbuf,4);
134 ret ^= IVAL(md4_outbuf,8);
135 ret ^= IVAL(md4_outbuf,12);
137 DEBUG(10,("do_reseed: returning seed %lu\n", ret));
142 /*******************************************************************
143 Interface to the (hopefully) good crypto random number generator.
144 ********************************************************************/
146 void generate_random_buffer( unsigned char *out, int len, BOOL re_seed)
148 static BOOL done_reseed = False;
149 unsigned char tmp_buf[64];
150 unsigned char md4_buf[16];
153 if(!done_reseed || re_seed) {
154 srandom(do_reseed());
159 * Generate random numbers in chunks of 64 bytes,
160 * then md4 them & copy to the output buffer.
166 int copy_len = len > 16 ? 16 : len;
167 for( i = 0; i < 16; i++)
168 SIVAL(tmp_buf, i*4, random());
169 mdfour(md4_buf, tmp_buf, sizeof(tmp_buf));
170 memcpy(p, md4_buf, copy_len);