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"
25 #include "lib/util/samba_util.h"
26 #include "lib/util/debug.h"
30 * @brief Random number generation
34 generate a single random uint32_t
36 _PUBLIC_
uint32_t generate_random(void)
39 generate_random_buffer(v
, 4);
44 @brief generate a random uint64
46 _PUBLIC_
uint64_t generate_random_u64(void)
49 generate_random_buffer(v
, 8);
54 * @brief Generate a random number in the given range.
56 * @param lower The lower value of the range
58 * @param upper The upper value of the range
60 * @return A random number bigger than than lower and smaller than upper.
62 _PUBLIC_
uint64_t generate_random_u64_range(uint64_t lower
, uint64_t upper
)
64 return generate_random_u64() % (upper
- lower
) + lower
;
67 _PUBLIC_
uint64_t generate_unique_u64(uint64_t veto_value
)
69 static struct generate_unique_u64_state
{
72 } generate_unique_u64_state
;
74 int pid
= tevent_cached_getpid();
76 if (unlikely(pid
!= generate_unique_u64_state
.pid
)) {
77 generate_unique_u64_state
= (struct generate_unique_u64_state
) {
79 .next_value
= veto_value
,
83 while (unlikely(generate_unique_u64_state
.next_value
== veto_value
)) {
84 generate_nonce_buffer(
85 (void *)&generate_unique_u64_state
.next_value
,
86 sizeof(generate_unique_u64_state
.next_value
));
89 return generate_unique_u64_state
.next_value
++;
93 Microsoft composed the following rules (among others) for quality
94 checks. This is an abridgment from
95 http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
97 Passwords must contain characters from three of the following five
100 - Uppercase characters of European languages (A through Z, with
101 diacritic marks, Greek and Cyrillic characters)
102 - Lowercase characters of European languages (a through z, sharp-s,
103 with diacritic marks, Greek and Cyrillic characters)
104 - Base 10 digits (0 through 9)
105 - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
106 - Any Unicode character that is categorized as an alphabetic character
107 but is not uppercase or lowercase. This includes Unicode characters
108 from Asian languages.
110 Note: for now do not check if the unicode category is
113 _PUBLIC_
bool check_password_quality(const char *pwd
)
116 size_t num_digits
= 0;
117 size_t num_upper
= 0;
118 size_t num_lower
= 0;
119 size_t num_nonalpha
= 0;
120 size_t num_unicode
= 0;
121 size_t num_categories
= 0;
128 const char *s
= &pwd
[ofs
];
132 c
= next_codepoint(s
, &len
);
133 if (c
== INVALID_CODEPOINT
) {
141 const char *na
= "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
164 * the rest does not belong to
181 * Note: for now do not check if the unicode category is
182 * alphabetic character
184 * We would have to import the details from
185 * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
191 if (num_digits
> 0) {
200 if (num_nonalpha
> 0) {
203 if (num_unicode
> 0) {
207 if (num_categories
>= 3) {
215 Use the random number generator to generate a random string.
218 _PUBLIC_
char *generate_random_str_list(TALLOC_CTX
*mem_ctx
, size_t len
, const char *list
)
221 size_t list_len
= strlen(list
);
223 char *retstr
= talloc_array(mem_ctx
, char, len
+ 1);
224 if (!retstr
) return NULL
;
226 generate_secret_buffer((uint8_t *)retstr
, len
);
227 for (i
= 0; i
< len
; i
++) {
228 retstr
[i
] = list
[retstr
[i
] % list_len
];
236 * Generate a random text string consisting of the specified length.
237 * The returned string will be allocated.
239 * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
242 _PUBLIC_
char *generate_random_str(TALLOC_CTX
*mem_ctx
, size_t len
)
245 const char *c_list
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
248 retstr
= generate_random_str_list(mem_ctx
, len
, c_list
);
249 if (!retstr
) return NULL
;
251 /* we need to make sure the random string passes basic quality tests
252 or it might be rejected by windows as a password */
253 if (len
>= 7 && !check_password_quality(retstr
)) {
262 * Generate a random text password (based on printable ascii characters).
265 _PUBLIC_
char *generate_random_password(TALLOC_CTX
*mem_ctx
, size_t min
, size_t max
)
268 /* This list does not include { or } because they cause
269 * problems for our provision (it can create a substring
270 * ${...}, and for Fedora DS (which treats {...} at the start
271 * of a stored password as special
272 * -- Andrew Bartlett 2010-03-11
274 const char *c_list
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
288 generate_secret_buffer((uint8_t *)&tmp
, sizeof(tmp
));
296 retstr
= generate_random_str_list(mem_ctx
, len
, c_list
);
297 if (!retstr
) return NULL
;
299 /* we need to make sure the random string passes basic quality tests
300 or it might be rejected by windows as a password */
301 if (len
>= 7 && !check_password_quality(retstr
)) {
310 * Generate a random machine password (based on random utf16 characters,
311 * converted to utf8). min must be at least 14, max must be at most 255.
313 * If 'unix charset' is not utf8, the password consist of random ascii
316 * The return value is a talloc string with destructor talloc_keep_secret() set.
317 * The content will be overwritten by zeros when the mem_ctx is destroyed.
320 _PUBLIC_
char *generate_random_machine_password(TALLOC_CTX
*mem_ctx
, size_t min
, size_t max
)
322 TALLOC_CTX
*frame
= NULL
;
323 struct generate_random_machine_password_state
{
324 uint8_t password_buffer
[256 * 2];
329 char *utf8_pw
= NULL
;
331 char *unix_pw
= NULL
;
353 frame
= talloc_stackframe_pool(2048);
354 state
= talloc_zero(frame
, struct generate_random_machine_password_state
);
355 talloc_keep_secret(state
);
362 generate_secret_buffer((uint8_t *)&tmp
, sizeof(tmp
));
370 * Create a random machine account password
371 * We create a random buffer and convert that to utf8.
372 * This is similar to what windows is doing.
374 * In future we may store the raw random buffer,
375 * but for now we need to pass the password as
376 * char pointer through some layers.
378 * As most kerberos keys are derived from the
379 * utf8 password we need to fallback to
380 * ASCII passwords if "unix charset" is not utf8.
382 generate_secret_buffer(state
->password_buffer
, len
* 2);
383 for (i
= 0; i
< len
; i
++) {
388 * both MIT krb5 and HEIMDAL only
389 * handle codepoints up to 0xffff.
391 * It means we need to avoid
392 * 0xD800 - 0xDBFF (high surrogate)
394 * 0xDC00 - 0xDFFF (low surrogate)
395 * in the random utf16 data.
397 * 55296 0xD800 0154000 0b1101100000000000
398 * 57343 0xDFFF 0157777 0b1101111111111111
399 * 8192 0x2000 020000 0b10000000000000
401 * The above values show that we can check
402 * for 0xD800 and just add 0x2000 to avoid
403 * the surrogate ranges.
405 * The rest will be handled by CH_UTF16MUNGED
406 * see utf16_munged_pull().
408 c
= SVAL(state
->password_buffer
, idx
);
412 SSVAL(state
->password_buffer
, idx
, c
);
414 ok
= convert_string_talloc(frame
,
415 CH_UTF16MUNGED
, CH_UTF8
,
416 state
->password_buffer
, len
* 2,
417 (void *)&utf8_pw
, &utf8_len
);
419 DEBUG(0, ("%s: convert_string_talloc() failed\n",
424 talloc_keep_secret(utf8_pw
);
426 ok
= convert_string_talloc(frame
,
427 CH_UTF16MUNGED
, CH_UNIX
,
428 state
->password_buffer
, len
* 2,
429 (void *)&unix_pw
, &unix_len
);
433 talloc_keep_secret(unix_pw
);
435 if (utf8_len
!= unix_len
) {
439 cmp
= memcmp((const uint8_t *)utf8_pw
,
440 (const uint8_t *)unix_pw
,
446 new_pw
= talloc_strdup(mem_ctx
, utf8_pw
);
447 if (new_pw
== NULL
) {
451 talloc_keep_secret(new_pw
);
452 talloc_set_name_const(new_pw
, __func__
);
457 for (i
= 0; i
< len
; i
++) {
461 state
->tmp
= state
->password_buffer
[i
] & 0x7f;
462 if (state
->tmp
== 0) {
463 state
->tmp
= state
->password_buffer
[i
] >> 1;
465 if (state
->tmp
== 0) {
468 state
->password_buffer
[i
] = state
->tmp
;
470 state
->password_buffer
[i
] = '\0';
472 new_pw
= talloc_strdup(mem_ctx
, (const char *)state
->password_buffer
);
473 if (new_pw
== NULL
) {
477 talloc_keep_secret(new_pw
);
478 talloc_set_name_const(new_pw
, __func__
);
484 * Generate an array of unique text strings all of the same length.
485 * The returned string will be allocated.
486 * Returns NULL if the number of unique combinations cannot be created.
488 * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
490 _PUBLIC_
char** generate_unique_strs(TALLOC_CTX
*mem_ctx
, size_t len
,
493 const char *c_list
= "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
494 const unsigned c_size
= 42;
499 if (num
== 0 || len
== 0)
502 strs
= talloc_array(mem_ctx
, char *, num
);
503 if (strs
== NULL
) return NULL
;
505 for (i
= 0; i
< num
; i
++) {
506 char *retstr
= (char *)talloc_size(strs
, len
+ 1);
507 if (retstr
== NULL
) {
512 for (j
= 0; j
< len
; j
++) {
513 retstr
[j
] = c_list
[rem
% c_size
];
519 /* we were not able to fit the number of
520 * combinations asked for in the length
522 DEBUG(0,(__location__
": Too many combinations %u for length %u\n",
523 num
, (unsigned)len
));