xref: /freebsd/crypto/heimdal/kadmin/random_password.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "kadmin_locl.h"
35b528cefcSMark Murray 
36b528cefcSMark Murray /* This file defines some a function that generates a random password,
37b528cefcSMark Murray    that can be used when creating a large amount of principals (such
38b528cefcSMark Murray    as for a batch of students). Since this is a political matter, you
39b528cefcSMark Murray    should think about how secure generated passwords has to be.
40b528cefcSMark Murray 
41b528cefcSMark Murray    Both methods defined here will give you at least 55 bits of
42b528cefcSMark Murray    entropy.
43b528cefcSMark Murray    */
44b528cefcSMark Murray 
45b528cefcSMark Murray /* If you want OTP-style passwords, define OTP_STYLE */
46b528cefcSMark Murray 
47b528cefcSMark Murray #ifdef OTP_STYLE
48b528cefcSMark Murray #include <otp.h>
49b528cefcSMark Murray #else
50b528cefcSMark Murray static void generate_password(char **pw, int num_classes, ...);
51b528cefcSMark Murray #endif
52b528cefcSMark Murray 
53b528cefcSMark Murray void
random_password(char * pw,size_t len)54b528cefcSMark Murray random_password(char *pw, size_t len)
55b528cefcSMark Murray {
56b528cefcSMark Murray #ifdef OTP_STYLE
57b528cefcSMark Murray     {
58adb0ddaeSAssar Westerlund 	OtpKey newkey;
59b528cefcSMark Murray 
60adb0ddaeSAssar Westerlund 	krb5_generate_random_block(&newkey, sizeof(newkey));
61b528cefcSMark Murray 	otp_print_stddict (newkey, pw, len);
62b528cefcSMark Murray 	strlwr(pw);
63b528cefcSMark Murray     }
64b528cefcSMark Murray #else
65b528cefcSMark Murray     char *pass;
66b528cefcSMark Murray     generate_password(&pass, 3,
67b528cefcSMark Murray 		      "abcdefghijklmnopqrstuvwxyz", 7,
68b528cefcSMark Murray 		      "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 2,
69b528cefcSMark Murray 		      "@$%&*()-+=:,/<>1234567890", 1);
70b528cefcSMark Murray     strlcpy(pw, pass, len);
71b528cefcSMark Murray     memset(pass, 0, strlen(pass));
72b528cefcSMark Murray     free(pass);
73b528cefcSMark Murray #endif
74b528cefcSMark Murray }
75b528cefcSMark Murray 
76b528cefcSMark Murray /* some helper functions */
77b528cefcSMark Murray 
78b528cefcSMark Murray #ifndef OTP_STYLE
79b528cefcSMark Murray /* return a random value in range 0-127 */
80b528cefcSMark Murray static int
RND(unsigned char * key,int keylen,int * left)81adb0ddaeSAssar Westerlund RND(unsigned char *key, int keylen, int *left)
82b528cefcSMark Murray {
83b528cefcSMark Murray     if(*left == 0){
84adb0ddaeSAssar Westerlund 	krb5_generate_random_block(key, keylen);
85adb0ddaeSAssar Westerlund 	*left = keylen;
86b528cefcSMark Murray     }
87b528cefcSMark Murray     (*left)--;
88b528cefcSMark Murray     return ((unsigned char*)key)[*left];
89b528cefcSMark Murray }
90b528cefcSMark Murray 
91b528cefcSMark Murray /* This a helper function that generates a random password with a
92b528cefcSMark Murray    number of characters from a set of character classes.
93b528cefcSMark Murray 
94b528cefcSMark Murray    If there are n classes, and the size of each class is Pi, and the
95b528cefcSMark Murray    number of characters from each class is Ni, the number of possible
96b528cefcSMark Murray    passwords are (given that the character classes are disjoint):
97b528cefcSMark Murray 
98b528cefcSMark Murray      n             n
99b528cefcSMark Murray    -----        /  ----  \
100b528cefcSMark Murray    |   |  Ni    |  \     |
101b528cefcSMark Murray    |   | Pi     |   \  Ni| !
102b528cefcSMark Murray    |   | ---- * |   /    |
103b528cefcSMark Murray    |   | Ni!    |  /___  |
104b528cefcSMark Murray     i=1          \  i=1  /
105b528cefcSMark Murray 
106b528cefcSMark Murray     Since it uses the RND function above, neither the size of each
107b528cefcSMark Murray     class, nor the total length of the generated password should be
108b528cefcSMark Murray     larger than 127 (without fixing RND).
109b528cefcSMark Murray 
110b528cefcSMark Murray    */
111b528cefcSMark Murray static void
generate_password(char ** pw,int num_classes,...)112b528cefcSMark Murray generate_password(char **pw, int num_classes, ...)
113b528cefcSMark Murray {
114b528cefcSMark Murray     struct {
115b528cefcSMark Murray 	const char *str;
116b528cefcSMark Murray 	int len;
117b528cefcSMark Murray 	int freq;
118b528cefcSMark Murray     } *classes;
119b528cefcSMark Murray     va_list ap;
120b528cefcSMark Murray     int len, i;
121adb0ddaeSAssar Westerlund     unsigned char rbuf[8]; /* random buffer */
122b528cefcSMark Murray     int rleft = 0;
123b528cefcSMark Murray 
124c19800e8SDoug Rabson     *pw = NULL;
125c19800e8SDoug Rabson 
126b528cefcSMark Murray     classes = malloc(num_classes * sizeof(*classes));
127c19800e8SDoug Rabson     if(classes == NULL)
128c19800e8SDoug Rabson 	return;
129b528cefcSMark Murray     va_start(ap, num_classes);
130b528cefcSMark Murray     len = 0;
131b528cefcSMark Murray     for(i = 0; i < num_classes; i++){
132b528cefcSMark Murray 	classes[i].str = va_arg(ap, const char*);
133b528cefcSMark Murray 	classes[i].len = strlen(classes[i].str);
134b528cefcSMark Murray 	classes[i].freq = va_arg(ap, int);
135b528cefcSMark Murray 	len += classes[i].freq;
136b528cefcSMark Murray     }
137b528cefcSMark Murray     va_end(ap);
138b528cefcSMark Murray     *pw = malloc(len + 1);
139c19800e8SDoug Rabson     if(*pw == NULL) {
140c19800e8SDoug Rabson 	free(classes);
141b528cefcSMark Murray 	return;
142c19800e8SDoug Rabson     }
143b528cefcSMark Murray     for(i = 0; i < len; i++) {
144b528cefcSMark Murray 	int j;
145adb0ddaeSAssar Westerlund 	int x = RND(rbuf, sizeof(rbuf), &rleft) % (len - i);
146b528cefcSMark Murray 	int t = 0;
147b528cefcSMark Murray 	for(j = 0; j < num_classes; j++) {
148b528cefcSMark Murray 	    if(x < t + classes[j].freq) {
149adb0ddaeSAssar Westerlund 		(*pw)[i] = classes[j].str[RND(rbuf, sizeof(rbuf), &rleft)
150adb0ddaeSAssar Westerlund 					 % classes[j].len];
151b528cefcSMark Murray 		classes[j].freq--;
152b528cefcSMark Murray 		break;
153b528cefcSMark Murray 	    }
154b528cefcSMark Murray 	    t += classes[j].freq;
155b528cefcSMark Murray 	}
156b528cefcSMark Murray     }
157b528cefcSMark Murray     (*pw)[len] = '\0';
158b528cefcSMark Murray     memset(rbuf, 0, sizeof(rbuf));
159b528cefcSMark Murray     free(classes);
160b528cefcSMark Murray }
161b528cefcSMark Murray #endif
162