]> jfr.im git - irc/rqf/shadowircd.git/blob - tools/mkpasswd.c
[svn r26332] get rid of the zip ready stuff
[irc/rqf/shadowircd.git] / tools / mkpasswd.c
1 /* simple password generator by Nelson Minar (minar@reed.edu)
2 ** copyright 1991, all rights reserved.
3 ** You can use this code as long as my name stays with it.
4 **
5 ** md5 patch by W. Campbell <wcampbel@botbay.net>
6 ** Modernization, getopt, etc for the Hybrid IRCD team
7 ** by W. Campbell
8 **
9 ** /dev/random for salt generation added by
10 ** Aaron Sethman <androsyn@ratbox.org>
11 **
12 ** $Id: mkpasswd.c 6 2005-09-10 01:02:21Z nenolod $
13 */
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <time.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20
21 #define FLAG_MD5 0x00000001
22 #define FLAG_DES 0x00000002
23 #define FLAG_SALT 0x00000004
24 #define FLAG_PASS 0x00000008
25 #define FLAG_LENGTH 0x00000010
26 #define FLAG_BLOWFISH 0x00000020
27 #define FLAG_ROUNDS 0x00000040
28 #define FLAG_EXT 0x00000080
29
30 extern char *getpass();
31 extern char *crypt();
32
33 static char *make_des_salt(void);
34 static char *make_ext_salt(int);
35 static char *make_ext_salt_para(int, char *);
36 static char *make_md5_salt(int);
37 static char *make_md5_salt_para(char *);
38 static char *make_bf_salt(int, int);
39 static char *make_bf_salt_para(int, char *);
40 static char *int_to_base64(int);
41 static char *generate_random_salt(char *, int);
42 static char *generate_poor_salt(char *, int);
43
44 static void full_usage(void);
45 static void brief_usage(void);
46
47 static char saltChars[] =
48 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
49 /* 0 .. 63, ascii - 64 */
50
51 extern char *optarg;
52
53 int main(int argc, char *argv[])
54 {
55 char *plaintext = NULL;
56 int c;
57 char *saltpara = NULL;
58 char *salt;
59 int flag = 0;
60 int length = 0; /* Not Set */
61 int rounds = 0; /* Not set, since extended DES needs 25 and blowfish needs
62 ** 4 by default, a side effect of this being the encryption
63 ** type parameter must be specified before the rounds
64 ** parameter.
65 */
66
67 while( (c=getopt(argc, argv, "mdber:h?l:s:p:")) != -1)
68 {
69 switch(c)
70 {
71 case 'm':
72 flag |= FLAG_MD5;
73 break;
74 case 'd':
75 flag |= FLAG_DES;
76 break;
77 case 'b':
78 flag |= FLAG_BLOWFISH;
79 rounds = 4;
80 break;
81 case 'e':
82 flag |= FLAG_EXT;
83 rounds = 25;
84 break;
85 case 'l':
86 flag |= FLAG_LENGTH;
87 length = atoi(optarg);
88 break;
89 case 'r':
90 flag |= FLAG_ROUNDS;
91 rounds = atoi(optarg);
92 break;
93 case 's':
94 flag |= FLAG_SALT;
95 saltpara = optarg;
96 break;
97 case 'p':
98 flag |= FLAG_PASS;
99 plaintext = optarg;
100 break;
101 case 'h':
102 full_usage();
103 /* NOT REACHED */
104 break;
105 case '?':
106 brief_usage();
107 /* NOT REACHED */
108 break;
109 default:
110 printf("Invalid Option: -%c\n", c);
111 break;
112 }
113 }
114
115 if (flag & FLAG_MD5)
116 {
117 if (length == 0)
118 length = 8;
119 if (flag & FLAG_SALT)
120 salt = make_md5_salt_para(saltpara);
121 else
122 salt = make_md5_salt(length);
123 }
124 else if (flag & FLAG_BLOWFISH)
125 {
126 if (length == 0)
127 length = 22;
128 if (flag & FLAG_SALT)
129 salt = make_bf_salt_para(rounds, saltpara);
130 else
131 salt = make_bf_salt(rounds, length);
132 }
133 else if (flag & FLAG_EXT)
134 {
135 /* XXX - rounds needs to be done */
136 if (flag & FLAG_SALT)
137 {
138 if ((strlen(saltpara) == 4))
139 {
140 salt = make_ext_salt_para(rounds, saltpara);
141 }
142 else
143 {
144 printf("Invalid salt, please enter 4 alphanumeric characters\n");
145 exit(1);
146 }
147 }
148 else
149 {
150 salt = make_ext_salt(rounds);
151 }
152 }
153 else
154 {
155 if (flag & FLAG_SALT)
156 {
157 if ((strlen(saltpara) == 2))
158 {
159 salt = saltpara;
160 }
161 else
162 {
163 printf("Invalid salt, please enter 2 alphanumeric characters\n");
164 exit(1);
165 }
166 }
167 else
168 {
169 salt = make_des_salt();
170 }
171 }
172
173 if (flag & FLAG_PASS)
174 {
175 if (!plaintext)
176 printf("Please enter a valid password\n");
177 }
178 else
179 {
180 plaintext = getpass("plaintext: ");
181 }
182
183 printf("%s\n", crypt(plaintext, salt));
184 return 0;
185 }
186
187 static char *make_des_salt()
188 {
189 static char salt[3];
190 generate_random_salt(salt, 2);
191 salt[2] = '\0';
192 return salt;
193 }
194
195 char *int_to_base64(int value)
196 {
197 static char buf[5];
198 int i;
199
200 for (i = 0; i < 4; i++)
201 {
202 buf[i] = saltChars[value & 63];
203 value >>= 6; /* Right shifting 6 places is the same as dividing by 64 */
204 }
205
206 buf[i] = '\0'; /* not REALLY needed as it's static, and thus initialized
207 ** to \0.
208 */
209 return buf;
210 }
211
212 char *make_ext_salt(int rounds)
213 {
214 static char salt[10];
215
216 sprintf(salt, "_%s", int_to_base64(rounds));
217 generate_random_salt(&salt[5], 4);
218 salt[9] = '\0';
219 return salt;
220 }
221
222 char *make_ext_salt_para(int rounds, char *saltpara)
223 {
224 static char salt[10];
225
226 sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara);
227 return salt;
228 }
229
230 char *make_md5_salt_para(char *saltpara)
231 {
232 static char salt[21];
233 if (saltpara && (strlen(saltpara) <= 16))
234 {
235 /* sprintf used because of portability requirements, the length
236 ** is checked above, so it should not be too much of a concern
237 */
238 sprintf(salt, "$1$%s$", saltpara);
239 return salt;
240 }
241 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
242 exit(1);
243
244 /* NOT REACHED */
245 return NULL;
246 }
247
248 char *make_md5_salt(int length)
249 {
250 static char salt[21];
251 if (length > 16)
252 {
253 printf("MD5 salt length too long\n");
254 exit(0);
255 }
256 salt[0] = '$';
257 salt[1] = '1';
258 salt[2] = '$';
259 generate_random_salt(&salt[3], length);
260 salt[length+3] = '$';
261 salt[length+4] = '\0';
262 return salt;
263 }
264
265 char *make_bf_salt_para(int rounds, char *saltpara)
266 {
267 static char salt[31];
268 char tbuf[3];
269 if (saltpara && (strlen(saltpara) <= 22))
270 {
271 /* sprintf used because of portability requirements, the length
272 ** is checked above, so it should not be too much of a concern
273 */
274 sprintf(tbuf, "%02d", rounds);
275 sprintf(salt, "$2a$%s$%s$", tbuf, saltpara);
276 return salt;
277 }
278 printf("Invalid Salt, please use up to 22 random alphanumeric characters\n");
279 exit(1);
280
281 /* NOT REACHED */
282 return NULL;
283 }
284
285 char *make_bf_salt(int rounds, int length)
286 {
287 static char salt[31];
288 char tbuf[3];
289 if (length > 22)
290 {
291 printf("BlowFish salt length too long\n");
292 exit(0);
293 }
294 sprintf(tbuf, "%02d", rounds);
295 sprintf(salt, "$2a$%s$", tbuf);
296 generate_random_salt(&salt[7], length);
297 salt[length+7] = '$';
298 salt[length+8] = '\0';
299 return salt;
300 }
301
302 char *generate_poor_salt(char *salt, int length)
303 {
304 int i;
305 srandom(time(NULL));
306 for(i = 0; i < length; i++)
307 {
308 salt[i] = saltChars[random() % 64];
309 }
310 return(salt);
311 }
312
313 char *generate_random_salt(char *salt, int length)
314 {
315 char *buf;
316 int fd, i;
317 if((fd = open("/dev/random", O_RDONLY)) < 0)
318 {
319 return(generate_poor_salt(salt, length));
320 }
321 buf = calloc(1, length);
322 if(read(fd, buf, length) != length)
323 {
324 free(buf);
325 return(generate_poor_salt(salt, length));
326 }
327
328 for(i = 0; i < length; i++)
329 {
330 salt[i] = saltChars[abs(buf[i]) % 64];
331 }
332 free(buf);
333 return(salt);
334 }
335
336 void full_usage()
337 {
338 printf("mkpasswd [-m|-d|-b|-e] [-l saltlength] [-r rounds] [-s salt] [-p plaintext]\n");
339 printf("-m Generate an MD5 password\n");
340 printf("-d Generate a DES password\n");
341 printf("-b Generate a BlowFish password\n");
342 printf("-e Generate an Extended DES password\n");
343 printf("-l Specify a length for a random MD5 or BlowFish salt\n");
344 printf("-r Specify a number of rounds for a BlowFish or Extended DES password\n");
345 printf(" BlowFish: default 4, no more than 6 recommended\n");
346 printf(" Extended DES: default 25\n");
347 printf("-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for MD5,\n");
348 printf(" up to 22 for BlowFish, and 4 for Extended DES\n");
349 printf("-p Specify a plaintext password to use\n");
350 printf("Example: mkpasswd -m -s 3dr -p test\n");
351 exit(0);
352 }
353
354 void brief_usage()
355 {
356 printf("mkpasswd - password hash generator\n");
357 printf("Standard DES: mkpasswd [-d] [-s salt] [-p plaintext]\n");
358 printf("Extended DES: mkpasswd -e [-r rounds] [-s salt] [-p plaintext]\n");
359 printf(" MD5: mkpasswd -m [-l saltlength] [-s salt] [-p plaintext]\n");
360 printf(" BlowFish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
361 printf(" [-p plaintext]\n");
362 printf("Use -h for full usage\n");
363 exit(0);
364 }