python:tests: Store keys as bytes rather than as lists of ints
[samba.git] / lib / util / genrand.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Functions to create reasonable random numbers for crypto use.
5
6    Copyright (C) Jeremy Allison 2001
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "../lib/crypto/crypto.h"
25 #include "system/locale.h"
26
27 /**
28  * @file
29  * @brief Random number generation
30  */
31
32 static unsigned char hash[258];
33 static uint32_t counter;
34
35 static bool done_reseed = false;
36 static unsigned int bytes_since_reseed = 0;
37
38 static int urand_fd = -1;
39
40 static void (*reseed_callback)(void *userdata, int *newseed);
41 static void *reseed_callback_userdata = NULL;
42
43 /**
44  Copy any user given reseed data.
45 **/
46
47 _PUBLIC_ void set_rand_reseed_callback(void (*fn)(void *, int *), void *userdata)
48 {
49         reseed_callback = fn;
50         reseed_callback_userdata = userdata;
51         set_need_random_reseed();
52 }
53
54 /**
55  * Tell the random number generator it needs to reseed.
56  */
57 _PUBLIC_ void set_need_random_reseed(void)
58 {
59         done_reseed = false;
60         bytes_since_reseed = 0;
61 }
62
63 static void get_rand_reseed_data(int *reseed_data)
64 {
65         if (reseed_callback) {
66                 reseed_callback(reseed_callback_userdata, reseed_data);
67         } else {
68                 *reseed_data = 0;
69         }
70 }
71
72 /**************************************************************** 
73  Setup the seed.
74 *****************************************************************/
75
76 static void seed_random_stream(unsigned char *seedval, size_t seedlen)
77 {
78         unsigned char j = 0;
79         size_t ind;
80
81         for (ind = 0; ind < 256; ind++)
82                 hash[ind] = (unsigned char)ind;
83
84         for( ind = 0; ind < 256; ind++) {
85                 unsigned char tc;
86
87                 j += (hash[ind] + seedval[ind%seedlen]);
88
89                 tc = hash[ind];
90                 hash[ind] = hash[j];
91                 hash[j] = tc;
92         }
93
94         hash[256] = 0;
95         hash[257] = 0;
96 }
97
98 /**************************************************************** 
99  Get datasize bytes worth of random data.
100 *****************************************************************/
101
102 static void get_random_stream(unsigned char *data, size_t datasize)
103 {
104         unsigned char index_i = hash[256];
105         unsigned char index_j = hash[257];
106         size_t ind;
107
108         for( ind = 0; ind < datasize; ind++) {
109                 unsigned char tc;
110                 unsigned char t;
111
112                 index_i++;
113                 index_j += hash[index_i];
114
115                 tc = hash[index_i];
116                 hash[index_i] = hash[index_j];
117                 hash[index_j] = tc;
118
119                 t = hash[index_i] + hash[index_j];
120                 data[ind] = hash[t];
121         }
122
123         hash[256] = index_i;
124         hash[257] = index_j;
125 }
126
127 /****************************************************************
128  Get a 16 byte hash from the contents of a file.  
129
130  Note that the hash is initialised, because the extra entropy is not
131  worth the valgrind pain.
132 *****************************************************************/
133
134 static void do_filehash(const char *fname, unsigned char *the_hash)
135 {
136         unsigned char buf[1011]; /* deliberate weird size */
137         unsigned char tmp_md4[16];
138         int fd, n;
139
140         ZERO_STRUCT(tmp_md4);
141
142         fd = open(fname,O_RDONLY,0);
143         if (fd == -1)
144                 return;
145
146         while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
147                 mdfour(tmp_md4, buf, n);
148                 for (n=0;n<16;n++)
149                         the_hash[n] ^= tmp_md4[n];
150         }
151         close(fd);
152 }
153
154 /**************************************************************
155  Try and get a good random number seed. Try a number of
156  different factors. Firstly, try /dev/urandom - use if exists.
157
158  We use /dev/urandom as a read of /dev/random can block if
159  the entropy pool dries up. This leads clients to timeout
160  or be very slow on connect.
161
162  If we can't use /dev/urandom then seed the stream random generator
163  above...
164 **************************************************************/
165
166 static int do_reseed(bool use_fd, int fd)
167 {
168         unsigned char seed_inbuf[40];
169         uint32_t v1, v2; struct timeval tval; pid_t mypid;
170         int reseed_data = 0;
171
172         if (use_fd) {
173                 if (fd == -1) {
174                         fd = open( "/dev/urandom", O_RDONLY,0);
175                         if (fd != -1) {
176                                 smb_set_close_on_exec(fd);
177                         }
178                 }
179                 if (fd != -1
180                     && (read(fd, seed_inbuf, sizeof(seed_inbuf)) == sizeof(seed_inbuf))) {
181                         seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
182                         return fd;
183                 }
184         }
185
186         /* Add in some secret file contents */
187
188         do_filehash("/etc/shadow", &seed_inbuf[0]);
189
190         /*
191          * Add the counter, time of day, and pid.
192          */
193
194         GetTimeOfDay(&tval);
195         mypid = getpid();
196         v1 = (counter++) + mypid + tval.tv_sec;
197         v2 = (counter++) * mypid + tval.tv_usec;
198
199         SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
200         SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
201
202         /*
203          * Add any user-given reseed data.
204          */
205
206         get_rand_reseed_data(&reseed_data);
207         if (reseed_data) {
208                 size_t i;
209                 for (i = 0; i < sizeof(seed_inbuf); i++)
210                         seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)];
211         }
212
213         seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
214
215         return -1;
216 }
217
218 /**
219  Interface to the (hopefully) good crypto random number generator.
220  Will use our internal PRNG if more than 40 bytes of random generation
221  has been requested, otherwise tries to read from /dev/random
222 **/
223 _PUBLIC_ void generate_random_buffer(uint8_t *out, int len)
224 {
225         unsigned char md4_buf[64];
226         unsigned char tmp_buf[16];
227         unsigned char *p;
228
229         if(!done_reseed) {
230                 bytes_since_reseed += len;
231                 
232                 /* Magic constant to try and avoid reading 40 bytes
233                  * and setting up the PRNG if the app only ever wants
234                  * a few bytes */
235                 if (bytes_since_reseed < 40) {
236                         if (urand_fd == -1) {
237                                 urand_fd = open( "/dev/urandom", O_RDONLY,0);
238                                 if (urand_fd != -1) {
239                                         smb_set_close_on_exec(urand_fd);
240                                 }
241                         }
242                         if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
243                                 return;
244                         }
245                 }
246
247                 urand_fd = do_reseed(true, urand_fd);
248                 done_reseed = true;
249         }
250
251         /*
252          * Generate random numbers in chunks of 64 bytes,
253          * then md4 them & copy to the output buffer.
254          * This way the raw state of the stream is never externally
255          * seen.
256          */
257
258         p = out;
259         while(len > 0) {
260                 int copy_len = len > 16 ? 16 : len;
261
262                 get_random_stream(md4_buf, sizeof(md4_buf));
263                 mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
264                 memcpy(p, tmp_buf, copy_len);
265                 p += copy_len;
266                 len -= copy_len;
267         }
268 }
269
270 /**
271  Interface to the (hopefully) good crypto random number generator.
272  Will always use /dev/urandom if available.
273 **/
274 _PUBLIC_ void generate_secret_buffer(uint8_t *out, int len)
275 {
276         if (urand_fd == -1) {
277                 urand_fd = open( "/dev/urandom", O_RDONLY,0);
278                 if (urand_fd != -1) {
279                         smb_set_close_on_exec(urand_fd);
280                 }
281         }
282         if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
283                 return;
284         }
285         
286         generate_random_buffer(out, len);
287 }
288
289 /**
290   generate a single random uint32_t
291 **/
292 _PUBLIC_ uint32_t generate_random(void)
293 {
294         uint8_t v[4];
295         generate_random_buffer(v, 4);
296         return IVAL(v, 0);
297 }
298
299
300 /**
301   Microsoft composed the following rules (among others) for quality
302   checks. This is an abridgment from
303   http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
304
305   Passwords must contain characters from three of the following five
306   categories:
307
308    - Uppercase characters of European languages (A through Z, with
309      diacritic marks, Greek and Cyrillic characters)
310    - Lowercase characters of European languages (a through z, sharp-s,
311      with diacritic marks, Greek and Cyrillic characters)
312    - Base 10 digits (0 through 9)
313    - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
314    - Any Unicode character that is categorized as an alphabetic character
315      but is not uppercase or lowercase. This includes Unicode characters
316      from Asian languages.
317
318  Note: for now do not check if the unicode category is
319        alphabetic character
320 **/
321 _PUBLIC_ bool check_password_quality(const char *pwd)
322 {
323         size_t ofs = 0;
324         size_t num_chars = 0;
325         size_t num_digits = 0;
326         size_t num_upper = 0;
327         size_t num_lower = 0;
328         size_t num_nonalpha = 0;
329         size_t num_unicode = 0;
330         size_t num_categories = 0;
331
332         if (pwd == NULL) {
333                 return false;
334         }
335
336         while (true) {
337                 const char *s = &pwd[ofs];
338                 size_t len = 0;
339                 codepoint_t c;
340
341                 c = next_codepoint(s, &len);
342                 if (c == INVALID_CODEPOINT) {
343                         return false;
344                 } else if (c == 0) {
345                         break;
346                 }
347                 ofs += len;
348                 num_chars += 1;
349
350                 if (len == 1) {
351                         const char *na = "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
352
353                         if (isdigit(c)) {
354                                 num_digits += 1;
355                                 continue;
356                         }
357
358                         if (isupper(c)) {
359                                 num_upper += 1;
360                                 continue;
361                         }
362
363                         if (islower(c)) {
364                                 num_lower += 1;
365                                 continue;
366                         }
367
368                         if (strchr(na, c)) {
369                                 num_nonalpha += 1;
370                                 continue;
371                         }
372
373                         /*
374                          * the rest does not belong to
375                          * a category.
376                          */
377                         continue;
378                 }
379
380                 if (isupper_m(c)) {
381                         num_upper += 1;
382                         continue;
383                 }
384
385                 if (islower_m(c)) {
386                         num_lower += 1;
387                         continue;
388                 }
389
390                 /*
391                  * Note: for now do not check if the unicode category is
392                  *       alphabetic character
393                  *
394                  * We would have to import the details from
395                  * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
396                  */
397                 num_unicode += 1;
398                 continue;
399         }
400
401         if (num_digits > 0) {
402                 num_categories += 1;
403         }
404         if (num_upper > 0) {
405                 num_categories += 1;
406         }
407         if (num_lower > 0) {
408                 num_categories += 1;
409         }
410         if (num_nonalpha > 0) {
411                 num_categories += 1;
412         }
413         if (num_unicode > 0) {
414                 num_categories += 1;
415         }
416
417         if (num_categories >= 3) {
418                 return true;
419         }
420
421         return false;
422 }
423
424 /**
425  Use the random number generator to generate a random string.
426 **/
427
428 _PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
429 {
430         size_t i;
431         size_t list_len = strlen(list);
432
433         char *retstr = talloc_array(mem_ctx, char, len + 1);
434         if (!retstr) return NULL;
435
436         generate_random_buffer((uint8_t *)retstr, len);
437         for (i = 0; i < len; i++) {
438                 retstr[i] = list[retstr[i] % list_len];
439         }
440         retstr[i] = '\0';
441
442         return retstr;
443 }
444
445 /**
446  * Generate a random text string consisting of the specified length.
447  * The returned string will be allocated.
448  *
449  * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
450  */
451
452 _PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
453 {
454         char *retstr;
455         const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
456
457 again:
458         retstr = generate_random_str_list(mem_ctx, len, c_list);
459         if (!retstr) return NULL;
460
461         /* we need to make sure the random string passes basic quality tests
462            or it might be rejected by windows as a password */
463         if (len >= 7 && !check_password_quality(retstr)) {
464                 talloc_free(retstr);
465                 goto again;
466         }
467
468         return retstr;
469 }
470
471 /**
472  * Generate a random text password.
473  */
474
475 _PUBLIC_ char *generate_random_password(TALLOC_CTX *mem_ctx, size_t min, size_t max)
476 {
477         char *retstr;
478         /* This list does not include { or } because they cause
479          * problems for our provision (it can create a substring
480          * ${...}, and for Fedora DS (which treats {...} at the start
481          * of a stored password as special 
482          *  -- Andrew Bartlett 2010-03-11
483          */
484         const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
485         size_t len = max;
486         size_t diff;
487
488         if (min > max) {
489                 errno = EINVAL;
490                 return NULL;
491         }
492
493         diff = max - min;
494
495         if (diff > 0 ) {
496                 size_t tmp;
497
498                 generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
499
500                 tmp %= diff;
501
502                 len = min + tmp;
503         }
504
505 again:
506         retstr = generate_random_str_list(mem_ctx, len, c_list);
507         if (!retstr) return NULL;
508
509         /* we need to make sure the random string passes basic quality tests
510            or it might be rejected by windows as a password */
511         if (len >= 7 && !check_password_quality(retstr)) {
512                 talloc_free(retstr);
513                 goto again;
514         }
515
516         return retstr;
517 }
518
519 /**
520  * Generate an array of unique text strings all of the same length.
521  * The returned string will be allocated.
522  * Returns NULL if the number of unique combinations cannot be created.
523  *
524  * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
525  */
526 _PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
527                                      uint32_t num)
528 {
529         const char *c_list = "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
530         const unsigned c_size = 42;
531         int i, j;
532         unsigned rem;
533         char ** strs = NULL;
534
535         if (num == 0 || len == 0)
536                 return NULL;
537
538         strs = talloc_array(mem_ctx, char *, num);
539         if (strs == NULL) return NULL;
540
541         for (i = 0; i < num; i++) {
542                 char *retstr = (char *)talloc_size(strs, len + 1);
543                 if (retstr == NULL) {
544                         talloc_free(strs);
545                         return NULL;
546                 }
547                 rem = i;
548                 for (j = 0; j < len; j++) {
549                         retstr[j] = c_list[rem % c_size];
550                         rem = rem / c_size;
551                 }
552                 retstr[j] = 0;
553                 strs[i] = retstr;
554                 if (rem != 0) {
555                         /* we were not able to fit the number of
556                          * combinations asked for in the length
557                          * specified */
558                         DEBUG(0,(__location__ ": Too many combinations %u for length %u\n",
559                                  num, (unsigned)len));
560                                  
561                         talloc_free(strs);
562                         return NULL;                     
563                 }
564         }
565
566         return strs;
567 }