xref: /freebsd/crypto/heimdal/kadmin/random_password.c (revision c19800e8cd5640693f36f2040db4ab5e8d738146)
1b528cefcSMark Murray /*
2b528cefcSMark Murray  * 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 
36c19800e8SDoug Rabson RCSID("$Id: random_password.c 21745 2007-07-31 16:11:25Z lha $");
37b528cefcSMark Murray 
38b528cefcSMark Murray /* This file defines some a function that generates a random password,
39b528cefcSMark Murray    that can be used when creating a large amount of principals (such
40b528cefcSMark Murray    as for a batch of students). Since this is a political matter, you
41b528cefcSMark Murray    should think about how secure generated passwords has to be.
42b528cefcSMark Murray 
43b528cefcSMark Murray    Both methods defined here will give you at least 55 bits of
44b528cefcSMark Murray    entropy.
45b528cefcSMark Murray    */
46b528cefcSMark Murray 
47b528cefcSMark Murray /* If you want OTP-style passwords, define OTP_STYLE */
48b528cefcSMark Murray 
49b528cefcSMark Murray #ifdef OTP_STYLE
50b528cefcSMark Murray #include <otp.h>
51b528cefcSMark Murray #else
52b528cefcSMark Murray static void generate_password(char **pw, int num_classes, ...);
53b528cefcSMark Murray #endif
54b528cefcSMark Murray 
55b528cefcSMark Murray void
56b528cefcSMark Murray random_password(char *pw, size_t len)
57b528cefcSMark Murray {
58b528cefcSMark Murray #ifdef OTP_STYLE
59b528cefcSMark Murray     {
60adb0ddaeSAssar Westerlund 	OtpKey newkey;
61b528cefcSMark Murray 
62adb0ddaeSAssar Westerlund 	krb5_generate_random_block(&newkey, sizeof(newkey));
63b528cefcSMark Murray 	otp_print_stddict (newkey, pw, len);
64b528cefcSMark Murray 	strlwr(pw);
65b528cefcSMark Murray     }
66b528cefcSMark Murray #else
67b528cefcSMark Murray     char *pass;
68b528cefcSMark Murray     generate_password(&pass, 3,
69b528cefcSMark Murray 		      "abcdefghijklmnopqrstuvwxyz", 7,
70b528cefcSMark Murray 		      "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 2,
71b528cefcSMark Murray 		      "@$%&*()-+=:,/<>1234567890", 1);
72b528cefcSMark Murray     strlcpy(pw, pass, len);
73b528cefcSMark Murray     memset(pass, 0, strlen(pass));
74b528cefcSMark Murray     free(pass);
75b528cefcSMark Murray #endif
76b528cefcSMark Murray }
77b528cefcSMark Murray 
78b528cefcSMark Murray /* some helper functions */
79b528cefcSMark Murray 
80b528cefcSMark Murray #ifndef OTP_STYLE
81b528cefcSMark Murray /* return a random value in range 0-127 */
82b528cefcSMark Murray static int
83adb0ddaeSAssar Westerlund RND(unsigned char *key, int keylen, int *left)
84b528cefcSMark Murray {
85b528cefcSMark Murray     if(*left == 0){
86adb0ddaeSAssar Westerlund 	krb5_generate_random_block(key, keylen);
87adb0ddaeSAssar Westerlund 	*left = keylen;
88b528cefcSMark Murray     }
89b528cefcSMark Murray     (*left)--;
90b528cefcSMark Murray     return ((unsigned char*)key)[*left];
91b528cefcSMark Murray }
92b528cefcSMark Murray 
93b528cefcSMark Murray /* This a helper function that generates a random password with a
94b528cefcSMark Murray    number of characters from a set of character classes.
95b528cefcSMark Murray 
96b528cefcSMark Murray    If there are n classes, and the size of each class is Pi, and the
97b528cefcSMark Murray    number of characters from each class is Ni, the number of possible
98b528cefcSMark Murray    passwords are (given that the character classes are disjoint):
99b528cefcSMark Murray 
100b528cefcSMark Murray      n             n
101b528cefcSMark Murray    -----        /  ----  \
102b528cefcSMark Murray    |   |  Ni    |  \     |
103b528cefcSMark Murray    |   | Pi     |   \  Ni| !
104b528cefcSMark Murray    |   | ---- * |   /    |
105b528cefcSMark Murray    |   | Ni!    |  /___  |
106b528cefcSMark Murray     i=1          \  i=1  /
107b528cefcSMark Murray 
108b528cefcSMark Murray     Since it uses the RND function above, neither the size of each
109b528cefcSMark Murray     class, nor the total length of the generated password should be
110b528cefcSMark Murray     larger than 127 (without fixing RND).
111b528cefcSMark Murray 
112b528cefcSMark Murray    */
113b528cefcSMark Murray static void
114b528cefcSMark Murray generate_password(char **pw, int num_classes, ...)
115b528cefcSMark Murray {
116b528cefcSMark Murray     struct {
117b528cefcSMark Murray 	const char *str;
118b528cefcSMark Murray 	int len;
119b528cefcSMark Murray 	int freq;
120b528cefcSMark Murray     } *classes;
121b528cefcSMark Murray     va_list ap;
122b528cefcSMark Murray     int len, i;
123adb0ddaeSAssar Westerlund     unsigned char rbuf[8]; /* random buffer */
124b528cefcSMark Murray     int rleft = 0;
125b528cefcSMark Murray 
126c19800e8SDoug Rabson     *pw = NULL;
127c19800e8SDoug Rabson 
128b528cefcSMark Murray     classes = malloc(num_classes * sizeof(*classes));
129c19800e8SDoug Rabson     if(classes == NULL)
130c19800e8SDoug Rabson 	return;
131b528cefcSMark Murray     va_start(ap, num_classes);
132b528cefcSMark Murray     len = 0;
133b528cefcSMark Murray     for(i = 0; i < num_classes; i++){
134b528cefcSMark Murray 	classes[i].str = va_arg(ap, const char*);
135b528cefcSMark Murray 	classes[i].len = strlen(classes[i].str);
136b528cefcSMark Murray 	classes[i].freq = va_arg(ap, int);
137b528cefcSMark Murray 	len += classes[i].freq;
138b528cefcSMark Murray     }
139b528cefcSMark Murray     va_end(ap);
140b528cefcSMark Murray     *pw = malloc(len + 1);
141c19800e8SDoug Rabson     if(*pw == NULL) {
142c19800e8SDoug Rabson 	free(classes);
143b528cefcSMark Murray 	return;
144c19800e8SDoug Rabson     }
145b528cefcSMark Murray     for(i = 0; i < len; i++) {
146b528cefcSMark Murray 	int j;
147adb0ddaeSAssar Westerlund 	int x = RND(rbuf, sizeof(rbuf), &rleft) % (len - i);
148b528cefcSMark Murray 	int t = 0;
149b528cefcSMark Murray 	for(j = 0; j < num_classes; j++) {
150b528cefcSMark Murray 	    if(x < t + classes[j].freq) {
151adb0ddaeSAssar Westerlund 		(*pw)[i] = classes[j].str[RND(rbuf, sizeof(rbuf), &rleft)
152adb0ddaeSAssar Westerlund 					 % classes[j].len];
153b528cefcSMark Murray 		classes[j].freq--;
154b528cefcSMark Murray 		break;
155b528cefcSMark Murray 	    }
156b528cefcSMark Murray 	    t += classes[j].freq;
157b528cefcSMark Murray 	}
158b528cefcSMark Murray     }
159b528cefcSMark Murray     (*pw)[len] = '\0';
160b528cefcSMark Murray     memset(rbuf, 0, sizeof(rbuf));
161b528cefcSMark Murray     free(classes);
162b528cefcSMark Murray }
163b528cefcSMark Murray #endif
164