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);
53 Microsoft composed the following rules (among others) for quality
54 checks. This is an abridgment from
55 http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx:
57 Passwords must contain characters from three of the following five
60 - Uppercase characters of European languages (A through Z, with
61 diacritic marks, Greek and Cyrillic characters)
62 - Lowercase characters of European languages (a through z, sharp-s,
63 with diacritic marks, Greek and Cyrillic characters)
64 - Base 10 digits (0 through 9)
65 - Nonalphanumeric characters: ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
66 - Any Unicode character that is categorized as an alphabetic character
67 but is not uppercase or lowercase. This includes Unicode characters
70 Note: for now do not check if the unicode category is
73 _PUBLIC_
bool check_password_quality(const char *pwd
)
77 size_t num_digits
= 0;
80 size_t num_nonalpha
= 0;
81 size_t num_unicode
= 0;
82 size_t num_categories
= 0;
89 const char *s
= &pwd
[ofs
];
93 c
= next_codepoint(s
, &len
);
94 if (c
== INVALID_CODEPOINT
) {
103 const char *na
= "~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?/";
126 * the rest does not belong to
143 * Note: for now do not check if the unicode category is
144 * alphabetic character
146 * We would have to import the details from
147 * ftp://ftp.unicode.org/Public/6.3.0/ucd/UnicodeData-6.3.0d1.txt
153 if (num_digits
> 0) {
162 if (num_nonalpha
> 0) {
165 if (num_unicode
> 0) {
169 if (num_categories
>= 3) {
177 Use the random number generator to generate a random string.
180 _PUBLIC_
char *generate_random_str_list(TALLOC_CTX
*mem_ctx
, size_t len
, const char *list
)
183 size_t list_len
= strlen(list
);
185 char *retstr
= talloc_array(mem_ctx
, char, len
+ 1);
186 if (!retstr
) return NULL
;
188 generate_secret_buffer((uint8_t *)retstr
, len
);
189 for (i
= 0; i
< len
; i
++) {
190 retstr
[i
] = list
[retstr
[i
] % list_len
];
198 * Generate a random text string consisting of the specified length.
199 * The returned string will be allocated.
201 * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
204 _PUBLIC_
char *generate_random_str(TALLOC_CTX
*mem_ctx
, size_t len
)
207 const char *c_list
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
210 retstr
= generate_random_str_list(mem_ctx
, len
, c_list
);
211 if (!retstr
) return NULL
;
213 /* we need to make sure the random string passes basic quality tests
214 or it might be rejected by windows as a password */
215 if (len
>= 7 && !check_password_quality(retstr
)) {
224 * Generate a random text password (based on printable ascii characters).
227 _PUBLIC_
char *generate_random_password(TALLOC_CTX
*mem_ctx
, size_t min
, size_t max
)
230 /* This list does not include { or } because they cause
231 * problems for our provision (it can create a substring
232 * ${...}, and for Fedora DS (which treats {...} at the start
233 * of a stored password as special
234 * -- Andrew Bartlett 2010-03-11
236 const char *c_list
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,@$%&!?:;<=>()[]~";
250 generate_secret_buffer((uint8_t *)&tmp
, sizeof(tmp
));
258 retstr
= generate_random_str_list(mem_ctx
, len
, c_list
);
259 if (!retstr
) return NULL
;
261 /* we need to make sure the random string passes basic quality tests
262 or it might be rejected by windows as a password */
263 if (len
>= 7 && !check_password_quality(retstr
)) {
272 * Generate a random machine password (based on random utf16 characters,
273 * converted to utf8). min must be at least 14, max must be at most 255.
275 * If 'unix charset' is not utf8, the password consist of random ascii
279 _PUBLIC_
char *generate_random_machine_password(TALLOC_CTX
*mem_ctx
, size_t min
, size_t max
)
281 TALLOC_CTX
*frame
= NULL
;
282 struct generate_random_machine_password_state
{
283 uint8_t password_buffer
[256 * 2];
288 char *utf8_pw
= NULL
;
290 char *unix_pw
= NULL
;
312 frame
= talloc_stackframe_pool(2048);
313 state
= talloc_zero(frame
, struct generate_random_machine_password_state
);
320 generate_secret_buffer((uint8_t *)&tmp
, sizeof(tmp
));
328 * Create a random machine account password
329 * We create a random buffer and convert that to utf8.
330 * This is similar to what windows is doing.
332 * In future we may store the raw random buffer,
333 * but for now we need to pass the password as
334 * char pointer through some layers.
336 * As most kerberos keys are derived from the
337 * utf8 password we need to fallback to
338 * ASCII passwords if "unix charset" is not utf8.
340 generate_secret_buffer(state
->password_buffer
, len
* 2);
341 for (i
= 0; i
< len
; i
++) {
346 * both MIT krb5 and HEIMDAL only
347 * handle codepoints up to 0xffff.
349 * It means we need to avoid
350 * 0xD800 - 0xDBFF (high surrogate)
352 * 0xDC00 - 0xDFFF (low surrogate)
353 * in the random utf16 data.
355 * 55296 0xD800 0154000 0b1101100000000000
356 * 57343 0xDFFF 0157777 0b1101111111111111
357 * 8192 0x2000 020000 0b10000000000000
359 * The above values show that we can check
360 * for 0xD800 and just add 0x2000 to avoid
361 * the surrogate ranges.
363 * The rest will be handled by CH_UTF16MUNGED
364 * see utf16_munged_pull().
366 c
= SVAL(state
->password_buffer
, idx
);
370 SSVAL(state
->password_buffer
, idx
, c
);
372 ok
= convert_string_talloc(frame
,
373 CH_UTF16MUNGED
, CH_UTF8
,
374 state
->password_buffer
, len
* 2,
375 (void *)&utf8_pw
, &utf8_len
);
377 DEBUG(0, ("%s: convert_string_talloc() failed\n",
383 ok
= convert_string_talloc(frame
,
384 CH_UTF16MUNGED
, CH_UNIX
,
385 state
->password_buffer
, len
* 2,
386 (void *)&unix_pw
, &unix_len
);
391 if (utf8_len
!= unix_len
) {
395 cmp
= memcmp((const uint8_t *)utf8_pw
,
396 (const uint8_t *)unix_pw
,
402 new_pw
= talloc_strdup(mem_ctx
, utf8_pw
);
403 if (new_pw
== NULL
) {
407 talloc_set_name_const(new_pw
, __func__
);
412 for (i
= 0; i
< len
; i
++) {
416 state
->tmp
= state
->password_buffer
[i
] & 0x7f;
417 if (state
->tmp
== 0) {
418 state
->tmp
= state
->password_buffer
[i
] >> 1;
420 if (state
->tmp
== 0) {
423 state
->password_buffer
[i
] = state
->tmp
;
425 state
->password_buffer
[i
] = '\0';
427 new_pw
= talloc_strdup(mem_ctx
, (const char *)state
->password_buffer
);
428 if (new_pw
== NULL
) {
432 talloc_set_name_const(new_pw
, __func__
);
438 * Generate an array of unique text strings all of the same length.
439 * The returned string will be allocated.
440 * Returns NULL if the number of unique combinations cannot be created.
442 * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
444 _PUBLIC_
char** generate_unique_strs(TALLOC_CTX
*mem_ctx
, size_t len
,
447 const char *c_list
= "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
448 const unsigned c_size
= 42;
453 if (num
== 0 || len
== 0)
456 strs
= talloc_array(mem_ctx
, char *, num
);
457 if (strs
== NULL
) return NULL
;
459 for (i
= 0; i
< num
; i
++) {
460 char *retstr
= (char *)talloc_size(strs
, len
+ 1);
461 if (retstr
== NULL
) {
466 for (j
= 0; j
< len
; j
++) {
467 retstr
[j
] = c_list
[rem
% c_size
];
473 /* we were not able to fit the number of
474 * combinations asked for in the length
476 DEBUG(0,(__location__
": Too many combinations %u for length %u\n",
477 num
, (unsigned)len
));