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/locale.h"
27 * @brief Random number generation
31 generate a single random uint32_t
33 _PUBLIC_
uint32_t generate_random(void)
36 generate_random_buffer(v
, 4);
41 @brief generate a random uint64
43 _PUBLIC_
uint64_t generate_random_u64(void)
46 generate_random_buffer(v
, 8);
50 _PUBLIC_
uint64_t generate_unique_u64(uint64_t veto_value
)
52 static struct generate_unique_u64_state
{
55 } generate_unique_u64_state
;
59 if (unlikely(pid
!= generate_unique_u64_state
.pid
)) {
60 generate_unique_u64_state
= (struct generate_unique_u64_state
) {
62 .next_value
= veto_value
,
66 while (unlikely(generate_unique_u64_state
.next_value
== veto_value
)) {
67 generate_nonce_buffer(
68 (void *)&generate_unique_u64_state
.next_value
,
69 sizeof(generate_unique_u64_state
.next_value
));
72 return generate_unique_u64_state
.next_value
++;
76 Microsoft composed the following rules (among others) for quality
77 checks. This is an abridgment from
78 http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
80 Passwords must contain characters from three of the following five
83 - Uppercase characters of European languages (A through Z, with
84 diacritic marks, Greek and Cyrillic characters)
85 - Lowercase characters of European languages (a through z, sharp-s,
86 with diacritic marks, Greek and Cyrillic characters)
87 - Base 10 digits (0 through 9)
88 - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
89 - Any Unicode character that is categorized as an alphabetic character
90 but is not uppercase or lowercase. This includes Unicode characters
93 Note: for now do not check if the unicode category is
96 _PUBLIC_
bool check_password_quality(const char *pwd
)
100 size_t num_digits
= 0;
101 size_t num_upper
= 0;
102 size_t num_lower
= 0;
103 size_t num_nonalpha
= 0;
104 size_t num_unicode
= 0;
105 size_t num_categories
= 0;
112 const char *s
= &pwd
[ofs
];
116 c
= next_codepoint(s
, &len
);
117 if (c
== INVALID_CODEPOINT
) {
126 const char *na
= "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
149 * the rest does not belong to
166 * Note: for now do not check if the unicode category is
167 * alphabetic character
169 * We would have to import the details from
170 * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
176 if (num_digits
> 0) {
185 if (num_nonalpha
> 0) {
188 if (num_unicode
> 0) {
192 if (num_categories
>= 3) {
200 Use the random number generator to generate a random string.
203 _PUBLIC_
char *generate_random_str_list(TALLOC_CTX
*mem_ctx
, size_t len
, const char *list
)
206 size_t list_len
= strlen(list
);
208 char *retstr
= talloc_array(mem_ctx
, char, len
+ 1);
209 if (!retstr
) return NULL
;
211 generate_secret_buffer((uint8_t *)retstr
, len
);
212 for (i
= 0; i
< len
; i
++) {
213 retstr
[i
] = list
[retstr
[i
] % list_len
];
221 * Generate a random text string consisting of the specified length.
222 * The returned string will be allocated.
224 * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
227 _PUBLIC_
char *generate_random_str(TALLOC_CTX
*mem_ctx
, size_t len
)
230 const char *c_list
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
233 retstr
= generate_random_str_list(mem_ctx
, len
, c_list
);
234 if (!retstr
) return NULL
;
236 /* we need to make sure the random string passes basic quality tests
237 or it might be rejected by windows as a password */
238 if (len
>= 7 && !check_password_quality(retstr
)) {
247 * Generate a random text password (based on printable ascii characters).
250 _PUBLIC_
char *generate_random_password(TALLOC_CTX
*mem_ctx
, size_t min
, size_t max
)
253 /* This list does not include { or } because they cause
254 * problems for our provision (it can create a substring
255 * ${...}, and for Fedora DS (which treats {...} at the start
256 * of a stored password as special
257 * -- Andrew Bartlett 2010-03-11
259 const char *c_list
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
273 generate_secret_buffer((uint8_t *)&tmp
, sizeof(tmp
));
281 retstr
= generate_random_str_list(mem_ctx
, len
, c_list
);
282 if (!retstr
) return NULL
;
284 /* we need to make sure the random string passes basic quality tests
285 or it might be rejected by windows as a password */
286 if (len
>= 7 && !check_password_quality(retstr
)) {
295 * Generate a random machine password (based on random utf16 characters,
296 * converted to utf8). min must be at least 14, max must be at most 255.
298 * If 'unix charset' is not utf8, the password consist of random ascii
302 _PUBLIC_
char *generate_random_machine_password(TALLOC_CTX
*mem_ctx
, size_t min
, size_t max
)
304 TALLOC_CTX
*frame
= NULL
;
305 struct generate_random_machine_password_state
{
306 uint8_t password_buffer
[256 * 2];
311 char *utf8_pw
= NULL
;
313 char *unix_pw
= NULL
;
335 frame
= talloc_stackframe_pool(2048);
336 state
= talloc_zero(frame
, struct generate_random_machine_password_state
);
343 generate_secret_buffer((uint8_t *)&tmp
, sizeof(tmp
));
351 * Create a random machine account password
352 * We create a random buffer and convert that to utf8.
353 * This is similar to what windows is doing.
355 * In future we may store the raw random buffer,
356 * but for now we need to pass the password as
357 * char pointer through some layers.
359 * As most kerberos keys are derived from the
360 * utf8 password we need to fallback to
361 * ASCII passwords if "unix charset" is not utf8.
363 generate_secret_buffer(state
->password_buffer
, len
* 2);
364 for (i
= 0; i
< len
; i
++) {
369 * both MIT krb5 and HEIMDAL only
370 * handle codepoints up to 0xffff.
372 * It means we need to avoid
373 * 0xD800 - 0xDBFF (high surrogate)
375 * 0xDC00 - 0xDFFF (low surrogate)
376 * in the random utf16 data.
378 * 55296 0xD800 0154000 0b1101100000000000
379 * 57343 0xDFFF 0157777 0b1101111111111111
380 * 8192 0x2000 020000 0b10000000000000
382 * The above values show that we can check
383 * for 0xD800 and just add 0x2000 to avoid
384 * the surrogate ranges.
386 * The rest will be handled by CH_UTF16MUNGED
387 * see utf16_munged_pull().
389 c
= SVAL(state
->password_buffer
, idx
);
393 SSVAL(state
->password_buffer
, idx
, c
);
395 ok
= convert_string_talloc(frame
,
396 CH_UTF16MUNGED
, CH_UTF8
,
397 state
->password_buffer
, len
* 2,
398 (void *)&utf8_pw
, &utf8_len
);
400 DEBUG(0, ("%s: convert_string_talloc() failed\n",
406 ok
= convert_string_talloc(frame
,
407 CH_UTF16MUNGED
, CH_UNIX
,
408 state
->password_buffer
, len
* 2,
409 (void *)&unix_pw
, &unix_len
);
414 if (utf8_len
!= unix_len
) {
418 cmp
= memcmp((const uint8_t *)utf8_pw
,
419 (const uint8_t *)unix_pw
,
425 new_pw
= talloc_strdup(mem_ctx
, utf8_pw
);
426 if (new_pw
== NULL
) {
430 talloc_set_name_const(new_pw
, __func__
);
435 for (i
= 0; i
< len
; i
++) {
439 state
->tmp
= state
->password_buffer
[i
] & 0x7f;
440 if (state
->tmp
== 0) {
441 state
->tmp
= state
->password_buffer
[i
] >> 1;
443 if (state
->tmp
== 0) {
446 state
->password_buffer
[i
] = state
->tmp
;
448 state
->password_buffer
[i
] = '\0';
450 new_pw
= talloc_strdup(mem_ctx
, (const char *)state
->password_buffer
);
451 if (new_pw
== NULL
) {
455 talloc_set_name_const(new_pw
, __func__
);
461 * Generate an array of unique text strings all of the same length.
462 * The returned string will be allocated.
463 * Returns NULL if the number of unique combinations cannot be created.
465 * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
467 _PUBLIC_
char** generate_unique_strs(TALLOC_CTX
*mem_ctx
, size_t len
,
470 const char *c_list
= "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
471 const unsigned c_size
= 42;
476 if (num
== 0 || len
== 0)
479 strs
= talloc_array(mem_ctx
, char *, num
);
480 if (strs
== NULL
) return NULL
;
482 for (i
= 0; i
< num
; i
++) {
483 char *retstr
= (char *)talloc_size(strs
, len
+ 1);
484 if (retstr
== NULL
) {
489 for (j
= 0; j
< len
; j
++) {
490 retstr
[j
] = c_list
[rem
% c_size
];
496 /* we were not able to fit the number of
497 * combinations asked for in the length
499 DEBUG(0,(__location__
": Too many combinations %u for length %u\n",
500 num
, (unsigned)len
));