2 Unix SMB/CIFS implementation.
4 Functions to create reasonable random numbers for crypto use.
6 Copyright (C) Jeremy Allison 2001
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.
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.
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/>.
23 #include "system/filesys.h"
24 #include "../lib/crypto/crypto.h"
25 #include "system/locale.h"
29 * @brief Random number generation
32 static unsigned char hash
[258];
33 static uint32_t counter
;
35 static bool done_reseed
= false;
36 static unsigned int bytes_since_reseed
= 0;
38 static int urand_fd
= -1;
40 static void (*reseed_callback
)(void *userdata
, int *newseed
);
41 static void *reseed_callback_userdata
= NULL
;
44 Copy any user given reseed data.
47 _PUBLIC_
void set_rand_reseed_callback(void (*fn
)(void *, int *), void *userdata
)
50 reseed_callback_userdata
= userdata
;
51 set_need_random_reseed();
55 * Tell the random number generator it needs to reseed.
57 _PUBLIC_
void set_need_random_reseed(void)
60 bytes_since_reseed
= 0;
63 static void get_rand_reseed_data(int *reseed_data
)
65 if (reseed_callback
) {
66 reseed_callback(reseed_callback_userdata
, reseed_data
);
72 /****************************************************************
74 *****************************************************************/
76 static void seed_random_stream(unsigned char *seedval
, size_t seedlen
)
81 for (ind
= 0; ind
< 256; ind
++)
82 hash
[ind
] = (unsigned char)ind
;
84 for( ind
= 0; ind
< 256; ind
++) {
87 j
+= (hash
[ind
] + seedval
[ind
%seedlen
]);
98 /****************************************************************
99 Get datasize bytes worth of random data.
100 *****************************************************************/
102 static void get_random_stream(unsigned char *data
, size_t datasize
)
104 unsigned char index_i
= hash
[256];
105 unsigned char index_j
= hash
[257];
108 for( ind
= 0; ind
< datasize
; ind
++) {
113 index_j
+= hash
[index_i
];
116 hash
[index_i
] = hash
[index_j
];
119 t
= hash
[index_i
] + hash
[index_j
];
127 /****************************************************************
128 Get a 16 byte hash from the contents of a file.
130 Note that the hash is initialised, because the extra entropy is not
131 worth the valgrind pain.
132 *****************************************************************/
134 static void do_filehash(const char *fname
, unsigned char *the_hash
)
136 unsigned char buf
[1011]; /* deliberate weird size */
137 unsigned char tmp_md4
[16];
140 ZERO_STRUCT(tmp_md4
);
142 fd
= open(fname
,O_RDONLY
,0);
146 while ((n
= read(fd
, (char *)buf
, sizeof(buf
))) > 0) {
147 mdfour(tmp_md4
, buf
, n
);
149 the_hash
[n
] ^= tmp_md4
[n
];
154 /**************************************************************
155 Try and get a good random number seed. Try a number of
156 different factors. Firstly, try /dev/urandom - use if exists.
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.
162 If we can't use /dev/urandom then seed the stream random generator
164 **************************************************************/
166 static int do_reseed(int fd
)
168 unsigned char seed_inbuf
[40];
169 uint32_t v1
, v2
; struct timeval tval
; pid_t mypid
;
173 fd
= open( "/dev/urandom", O_RDONLY
,0);
175 smb_set_close_on_exec(fd
);
179 && (read(fd
, seed_inbuf
, sizeof(seed_inbuf
)) == sizeof(seed_inbuf
))) {
180 seed_random_stream(seed_inbuf
, sizeof(seed_inbuf
));
184 /* Add in some secret file contents */
186 do_filehash("/etc/shadow", &seed_inbuf
[0]);
189 * Add the counter, time of day, and pid.
194 v1
= (counter
++) + mypid
+ tval
.tv_sec
;
195 v2
= (counter
++) * mypid
+ tval
.tv_usec
;
197 SIVAL(seed_inbuf
, 32, v1
^ IVAL(seed_inbuf
, 32));
198 SIVAL(seed_inbuf
, 36, v2
^ IVAL(seed_inbuf
, 36));
201 * Add any user-given reseed data.
204 get_rand_reseed_data(&reseed_data
);
207 for (i
= 0; i
< sizeof(seed_inbuf
); i
++)
208 seed_inbuf
[i
] ^= ((char *)(&reseed_data
))[i
% sizeof(reseed_data
)];
211 seed_random_stream(seed_inbuf
, sizeof(seed_inbuf
));
217 Interface to the (hopefully) good crypto random number generator.
218 Will use our internal PRNG if more than 40 bytes of random generation
219 has been requested, otherwise tries to read from /dev/random
221 _PUBLIC_
void generate_random_buffer(uint8_t *out
, int len
)
223 unsigned char md4_buf
[64];
224 unsigned char tmp_buf
[16];
228 bytes_since_reseed
+= len
;
230 /* Magic constant to try and avoid reading 40 bytes
231 * and setting up the PRNG if the app only ever wants
233 if (bytes_since_reseed
< 40) {
234 if (urand_fd
== -1) {
235 urand_fd
= open( "/dev/urandom", O_RDONLY
,0);
236 if (urand_fd
!= -1) {
237 smb_set_close_on_exec(urand_fd
);
240 if(urand_fd
!= -1 && (read(urand_fd
, out
, len
) == len
)) {
245 urand_fd
= do_reseed(urand_fd
);
250 * Generate random numbers in chunks of 64 bytes,
251 * then md4 them & copy to the output buffer.
252 * This way the raw state of the stream is never externally
258 int copy_len
= len
> 16 ? 16 : len
;
260 get_random_stream(md4_buf
, sizeof(md4_buf
));
261 mdfour(tmp_buf
, md4_buf
, sizeof(md4_buf
));
262 memcpy(p
, tmp_buf
, copy_len
);
269 Interface to the (hopefully) good crypto random number generator.
270 Will always use /dev/urandom if available.
272 _PUBLIC_
void generate_secret_buffer(uint8_t *out
, int len
)
274 if (urand_fd
== -1) {
275 urand_fd
= open( "/dev/urandom", O_RDONLY
,0);
276 if (urand_fd
!= -1) {
277 smb_set_close_on_exec(urand_fd
);
280 if(urand_fd
!= -1 && (read(urand_fd
, out
, len
) == len
)) {
284 generate_random_buffer(out
, len
);
288 generate a single random uint32_t
290 _PUBLIC_
uint32_t generate_random(void)
293 generate_random_buffer(v
, 4);
299 Microsoft composed the following rules (among others) for quality
300 checks. This is an abridgment from
301 http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
303 Passwords must contain characters from three of the following five
306 - Uppercase characters of European languages (A through Z, with
307 diacritic marks, Greek and Cyrillic characters)
308 - Lowercase characters of European languages (a through z, sharp-s,
309 with diacritic marks, Greek and Cyrillic characters)
310 - Base 10 digits (0 through 9)
311 - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
312 - Any Unicode character that is categorized as an alphabetic character
313 but is not uppercase or lowercase. This includes Unicode characters
314 from Asian languages.
316 Note: for now do not check if the unicode category is
319 _PUBLIC_
bool check_password_quality(const char *pwd
)
322 size_t num_chars
= 0;
323 size_t num_digits
= 0;
324 size_t num_upper
= 0;
325 size_t num_lower
= 0;
326 size_t num_nonalpha
= 0;
327 size_t num_unicode
= 0;
328 size_t num_categories
= 0;
335 const char *s
= &pwd
[ofs
];
339 c
= next_codepoint(s
, &len
);
340 if (c
== INVALID_CODEPOINT
) {
349 const char *na
= "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
372 * the rest does not belong to
389 * Note: for now do not check if the unicode category is
390 * alphabetic character
392 * We would have to import the details from
393 * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
399 if (num_digits
> 0) {
408 if (num_nonalpha
> 0) {
411 if (num_unicode
> 0) {
415 if (num_categories
>= 3) {
423 Use the random number generator to generate a random string.
426 _PUBLIC_
char *generate_random_str_list(TALLOC_CTX
*mem_ctx
, size_t len
, const char *list
)
429 size_t list_len
= strlen(list
);
431 char *retstr
= talloc_array(mem_ctx
, char, len
+ 1);
432 if (!retstr
) return NULL
;
434 generate_random_buffer((uint8_t *)retstr
, len
);
435 for (i
= 0; i
< len
; i
++) {
436 retstr
[i
] = list
[retstr
[i
] % list_len
];
444 * Generate a random text string consisting of the specified length.
445 * The returned string will be allocated.
447 * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
450 _PUBLIC_
char *generate_random_str(TALLOC_CTX
*mem_ctx
, size_t len
)
453 const char *c_list
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
456 retstr
= generate_random_str_list(mem_ctx
, len
, c_list
);
457 if (!retstr
) return NULL
;
459 /* we need to make sure the random string passes basic quality tests
460 or it might be rejected by windows as a password */
461 if (len
>= 7 && !check_password_quality(retstr
)) {
470 * Generate a random text password.
473 _PUBLIC_
char *generate_random_password(TALLOC_CTX
*mem_ctx
, size_t min
, size_t max
)
476 /* This list does not include { or } because they cause
477 * problems for our provision (it can create a substring
478 * ${...}, and for Fedora DS (which treats {...} at the start
479 * of a stored password as special
480 * -- Andrew Bartlett 2010-03-11
482 const char *c_list
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
496 generate_random_buffer((uint8_t *)&tmp
, sizeof(tmp
));
504 retstr
= generate_random_str_list(mem_ctx
, len
, c_list
);
505 if (!retstr
) return NULL
;
507 /* we need to make sure the random string passes basic quality tests
508 or it might be rejected by windows as a password */
509 if (len
>= 7 && !check_password_quality(retstr
)) {
518 * Generate an array of unique text strings all of the same length.
519 * The returned string will be allocated.
520 * Returns NULL if the number of unique combinations cannot be created.
522 * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
524 _PUBLIC_
char** generate_unique_strs(TALLOC_CTX
*mem_ctx
, size_t len
,
527 const char *c_list
= "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
528 const unsigned c_size
= 42;
533 if (num
== 0 || len
== 0)
536 strs
= talloc_array(mem_ctx
, char *, num
);
537 if (strs
== NULL
) return NULL
;
539 for (i
= 0; i
< num
; i
++) {
540 char *retstr
= (char *)talloc_size(strs
, len
+ 1);
541 if (retstr
== NULL
) {
546 for (j
= 0; j
< len
; j
++) {
547 retstr
[j
] = c_list
[rem
% c_size
];
553 /* we were not able to fit the number of
554 * combinations asked for in the length
556 DEBUG(0,(__location__
": Too many combinations %u for length %u\n",
557 num
, (unsigned)len
));