]>
Commit | Line | Data |
---|---|---|
212380e3 AC |
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 | ** | |
f1d07f6b | 12 | ** $Id: mkpasswd.c 26439 2009-02-01 15:27:24Z jilles $ |
212380e3 AC |
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> | |
f1d07f6b JT |
20 | #include "ratbox_lib.h" |
21 | #ifndef __MINGW32__ | |
22 | #include <pwd.h> | |
23 | #endif | |
212380e3 | 24 | |
f1d07f6b JT |
25 | #define FLAG_MD5 0x00000001 |
26 | #define FLAG_DES 0x00000002 | |
27 | #define FLAG_SALT 0x00000004 | |
28 | #define FLAG_PASS 0x00000008 | |
29 | #define FLAG_LENGTH 0x00000010 | |
212380e3 | 30 | #define FLAG_BLOWFISH 0x00000020 |
f1d07f6b JT |
31 | #define FLAG_ROUNDS 0x00000040 |
32 | #define FLAG_EXT 0x00000080 | |
33 | #define FLAG_SHA256 0x00000100 | |
34 | #define FLAG_SHA512 0x00000200 | |
212380e3 | 35 | |
212380e3 AC |
36 | |
37 | static char *make_des_salt(void); | |
38 | static char *make_ext_salt(int); | |
39 | static char *make_ext_salt_para(int, char *); | |
40 | static char *make_md5_salt(int); | |
41 | static char *make_md5_salt_para(char *); | |
f1d07f6b JT |
42 | static char *make_sha256_salt(int); |
43 | static char *make_sha256_salt_para(char *); | |
44 | static char *make_sha512_salt(int); | |
45 | static char *make_sha512_salt_para(char *); | |
212380e3 AC |
46 | static char *make_bf_salt(int, int); |
47 | static char *make_bf_salt_para(int, char *); | |
48 | static char *int_to_base64(int); | |
49 | static char *generate_random_salt(char *, int); | |
50 | static char *generate_poor_salt(char *, int); | |
51 | ||
52 | static void full_usage(void); | |
53 | static void brief_usage(void); | |
54 | ||
f1d07f6b | 55 | static char saltChars[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
212380e3 AC |
56 | /* 0 .. 63, ascii - 64 */ |
57 | ||
58 | extern char *optarg; | |
59 | ||
f1d07f6b JT |
60 | |
61 | #ifdef __MINGW32__ | |
62 | #include <conio.h> | |
63 | #ifdef PASS_MAX | |
64 | #undef PASS_MAX | |
65 | #endif | |
66 | #define PASS_MAX 256 | |
67 | static char getpassbuf[PASS_MAX + 1]; | |
68 | ||
69 | static char * | |
70 | getpass(const char *prompt) | |
212380e3 | 71 | { |
f1d07f6b JT |
72 | int c; |
73 | int i = 0; | |
74 | ||
75 | memset(getpassbuf, sizeof(getpassbuf), 0); | |
76 | fputs(prompt, stderr); | |
77 | for(;;) | |
78 | { | |
79 | c = _getch(); | |
80 | if(c == '\r') | |
81 | { | |
82 | getpassbuf[i] = '\0'; | |
83 | break; | |
84 | } | |
85 | else if(i < PASS_MAX) | |
86 | { | |
87 | getpassbuf[i++] = c; | |
88 | } | |
89 | } | |
90 | fputs("\r\n", stderr); | |
91 | ||
92 | return getpassbuf; | |
212380e3 | 93 | } |
f1d07f6b JT |
94 | #endif |
95 | ||
212380e3 | 96 | |
f1d07f6b JT |
97 | int |
98 | main(int argc, char *argv[]) | |
212380e3 | 99 | { |
f1d07f6b JT |
100 | char *plaintext = NULL; |
101 | int c; | |
102 | char *saltpara = NULL; | |
103 | char *salt; | |
104 | int flag = 0; | |
105 | int length = 0; /* Not Set */ | |
106 | int rounds = 0; /* Not set, since extended DES needs 25 and blowfish needs | |
107 | ** 4 by default, a side effect of this being the encryption | |
108 | ** type parameter must be specified before the rounds | |
109 | ** parameter. | |
110 | */ | |
111 | ||
112 | while((c = getopt(argc, argv, "xymdber:h?l:s:p:")) != -1) | |
113 | { | |
114 | switch (c) | |
115 | { | |
116 | case 'm': | |
117 | flag |= FLAG_MD5; | |
118 | break; | |
119 | case 'd': | |
120 | flag |= FLAG_DES; | |
121 | break; | |
122 | case 'b': | |
123 | flag |= FLAG_BLOWFISH; | |
124 | rounds = 4; | |
125 | break; | |
126 | case 'e': | |
127 | flag |= FLAG_EXT; | |
128 | rounds = 25; | |
129 | break; | |
130 | case 'l': | |
131 | flag |= FLAG_LENGTH; | |
132 | length = atoi(optarg); | |
133 | break; | |
134 | case 'r': | |
135 | flag |= FLAG_ROUNDS; | |
136 | rounds = atoi(optarg); | |
137 | break; | |
138 | case 's': | |
139 | flag |= FLAG_SALT; | |
140 | saltpara = optarg; | |
141 | break; | |
142 | case 'p': | |
143 | flag |= FLAG_PASS; | |
144 | plaintext = optarg; | |
145 | break; | |
146 | case 'x': | |
147 | flag |= FLAG_SHA256; | |
148 | break; | |
149 | case 'y': | |
150 | flag |= FLAG_SHA512; | |
151 | break; | |
152 | case 'h': | |
153 | full_usage(); | |
154 | /* NOT REACHED */ | |
155 | break; | |
156 | case '?': | |
157 | brief_usage(); | |
158 | /* NOT REACHED */ | |
159 | break; | |
160 | default: | |
161 | printf("Invalid Option: -%c\n", c); | |
162 | break; | |
163 | } | |
164 | } | |
165 | ||
166 | if(flag & FLAG_MD5) | |
167 | { | |
168 | if(length == 0) | |
169 | length = 8; | |
170 | if(flag & FLAG_SALT) | |
171 | salt = make_md5_salt_para(saltpara); | |
172 | else | |
173 | salt = make_md5_salt(length); | |
174 | } | |
175 | else if(flag & FLAG_BLOWFISH) | |
176 | { | |
177 | if(length == 0) | |
178 | length = 22; | |
179 | if(flag & FLAG_SALT) | |
180 | salt = make_bf_salt_para(rounds, saltpara); | |
181 | else | |
182 | salt = make_bf_salt(rounds, length); | |
183 | } | |
184 | else if(flag & FLAG_SHA256) | |
185 | { | |
186 | if(length == 0) | |
187 | length = 16; | |
188 | if(flag & FLAG_SALT) | |
189 | salt = make_sha256_salt_para(saltpara); | |
190 | else | |
191 | salt = make_sha256_salt(length); | |
192 | } | |
193 | else if(flag & FLAG_SHA512) | |
194 | { | |
195 | if(length == 0) | |
196 | length = 16; | |
197 | if(flag & FLAG_SALT) | |
198 | salt = make_sha512_salt_para(saltpara); | |
199 | else | |
200 | salt = make_sha512_salt(length); | |
201 | } | |
202 | else if(flag & FLAG_EXT) | |
203 | { | |
204 | /* XXX - rounds needs to be done */ | |
205 | if(flag & FLAG_SALT) | |
206 | { | |
207 | if((strlen(saltpara) == 4)) | |
208 | { | |
209 | salt = make_ext_salt_para(rounds, saltpara); | |
210 | } | |
211 | else | |
212 | { | |
213 | printf("Invalid salt, please enter 4 alphanumeric characters\n"); | |
214 | exit(1); | |
215 | } | |
216 | } | |
217 | else | |
218 | { | |
219 | salt = make_ext_salt(rounds); | |
220 | } | |
221 | } | |
222 | else | |
223 | { | |
224 | if(flag & FLAG_SALT) | |
225 | { | |
226 | if((strlen(saltpara) == 2)) | |
227 | { | |
228 | salt = saltpara; | |
229 | } | |
230 | else | |
231 | { | |
232 | printf("Invalid salt, please enter 2 alphanumeric characters\n"); | |
233 | exit(1); | |
234 | } | |
235 | } | |
236 | else | |
237 | { | |
238 | salt = make_des_salt(); | |
239 | } | |
240 | } | |
241 | ||
242 | if(flag & FLAG_PASS) | |
243 | { | |
244 | if(!plaintext) | |
245 | printf("Please enter a valid password\n"); | |
246 | } | |
247 | else | |
248 | { | |
249 | plaintext = getpass("plaintext: "); | |
250 | } | |
251 | ||
252 | printf("%s\n", rb_crypt(plaintext, salt)); | |
253 | return 0; | |
212380e3 AC |
254 | } |
255 | ||
f1d07f6b JT |
256 | static char * |
257 | make_des_salt() | |
212380e3 | 258 | { |
f1d07f6b JT |
259 | static char salt[3]; |
260 | generate_random_salt(salt, 2); | |
261 | salt[2] = '\0'; | |
262 | return salt; | |
212380e3 AC |
263 | } |
264 | ||
f1d07f6b JT |
265 | char * |
266 | int_to_base64(int value) | |
212380e3 | 267 | { |
f1d07f6b JT |
268 | static char buf[5]; |
269 | int i; | |
212380e3 | 270 | |
f1d07f6b JT |
271 | for(i = 0; i < 4; i++) |
272 | { | |
273 | buf[i] = saltChars[value & 63]; | |
274 | value >>= 6; /* Right shifting 6 places is the same as dividing by 64 */ | |
275 | } | |
276 | ||
277 | buf[i] = '\0'; /* not REALLY needed as it's static, and thus initialized | |
278 | ** to \0. | |
279 | */ | |
280 | return buf; | |
212380e3 AC |
281 | } |
282 | ||
f1d07f6b JT |
283 | char * |
284 | make_ext_salt(int rounds) | |
212380e3 | 285 | { |
f1d07f6b | 286 | static char salt[10]; |
212380e3 | 287 | |
f1d07f6b JT |
288 | sprintf(salt, "_%s", int_to_base64(rounds)); |
289 | generate_random_salt(&salt[5], 4); | |
290 | salt[9] = '\0'; | |
291 | return salt; | |
212380e3 AC |
292 | } |
293 | ||
f1d07f6b JT |
294 | char * |
295 | make_ext_salt_para(int rounds, char *saltpara) | |
212380e3 | 296 | { |
f1d07f6b JT |
297 | static char salt[10]; |
298 | ||
299 | sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara); | |
300 | return salt; | |
212380e3 | 301 | } |
f1d07f6b JT |
302 | |
303 | char * | |
304 | make_md5_salt_para(char *saltpara) | |
212380e3 | 305 | { |
f1d07f6b JT |
306 | static char salt[21]; |
307 | if(saltpara && (strlen(saltpara) <= 16)) | |
308 | { | |
309 | /* sprintf used because of portability requirements, the length | |
310 | ** is checked above, so it should not be too much of a concern | |
311 | */ | |
312 | sprintf(salt, "$1$%s$", saltpara); | |
313 | return salt; | |
314 | } | |
315 | printf("Invalid Salt, please use up to 16 random alphanumeric characters\n"); | |
316 | exit(1); | |
317 | ||
318 | /* NOT REACHED */ | |
319 | return NULL; | |
212380e3 AC |
320 | } |
321 | ||
f1d07f6b JT |
322 | char * |
323 | make_md5_salt(int length) | |
212380e3 | 324 | { |
f1d07f6b JT |
325 | static char salt[21]; |
326 | if(length > 16) | |
327 | { | |
328 | printf("MD5 salt length too long\n"); | |
329 | exit(0); | |
330 | } | |
331 | salt[0] = '$'; | |
332 | salt[1] = '1'; | |
333 | salt[2] = '$'; | |
334 | generate_random_salt(&salt[3], length); | |
335 | salt[length + 3] = '$'; | |
336 | salt[length + 4] = '\0'; | |
337 | return salt; | |
212380e3 AC |
338 | } |
339 | ||
f1d07f6b JT |
340 | char * |
341 | make_sha256_salt_para(char *saltpara) | |
212380e3 | 342 | { |
f1d07f6b JT |
343 | static char salt[21]; |
344 | if(saltpara && (strlen(saltpara) <= 16)) | |
345 | { | |
346 | /* sprintf used because of portability requirements, the length | |
347 | ** is checked above, so it should not be too much of a concern | |
348 | */ | |
349 | sprintf(salt, "$5$%s$", saltpara); | |
350 | return salt; | |
351 | } | |
352 | printf("Invalid Salt, please use up to 16 random alphanumeric characters\n"); | |
353 | exit(1); | |
354 | ||
355 | /* NOT REACHED */ | |
356 | return NULL; | |
212380e3 AC |
357 | } |
358 | ||
f1d07f6b JT |
359 | char * |
360 | make_sha512_salt_para(char *saltpara) | |
212380e3 | 361 | { |
f1d07f6b JT |
362 | static char salt[21]; |
363 | if(saltpara && (strlen(saltpara) <= 16)) | |
364 | { | |
365 | /* sprintf used because of portability requirements, the length | |
366 | ** is checked above, so it should not be too much of a concern | |
367 | */ | |
368 | sprintf(salt, "$6$%s$", saltpara); | |
369 | return salt; | |
370 | } | |
371 | printf("Invalid Salt, please use up to 16 random alphanumeric characters\n"); | |
372 | exit(1); | |
373 | ||
374 | /* NOT REACHED */ | |
375 | return NULL; | |
212380e3 AC |
376 | } |
377 | ||
f1d07f6b JT |
378 | |
379 | char * | |
380 | make_sha256_salt(int length) | |
212380e3 | 381 | { |
f1d07f6b JT |
382 | static char salt[21]; |
383 | if(length > 16) | |
384 | { | |
385 | printf("SHA256 salt length too long\n"); | |
386 | exit(0); | |
387 | } | |
388 | salt[0] = '$'; | |
389 | salt[1] = '5'; | |
390 | salt[2] = '$'; | |
391 | generate_random_salt(&salt[3], length); | |
392 | salt[length + 3] = '$'; | |
393 | salt[length + 4] = '\0'; | |
394 | return salt; | |
395 | } | |
396 | ||
397 | char * | |
398 | make_sha512_salt(int length) | |
399 | { | |
400 | static char salt[21]; | |
401 | if(length > 16) | |
402 | { | |
403 | printf("SHA512 salt length too long\n"); | |
404 | exit(0); | |
405 | } | |
406 | salt[0] = '$'; | |
407 | salt[1] = '6'; | |
408 | salt[2] = '$'; | |
409 | generate_random_salt(&salt[3], length); | |
410 | salt[length + 3] = '$'; | |
411 | salt[length + 4] = '\0'; | |
412 | return salt; | |
413 | } | |
414 | ||
415 | char * | |
416 | make_bf_salt_para(int rounds, char *saltpara) | |
417 | { | |
418 | static char salt[31]; | |
419 | char tbuf[3]; | |
420 | if(saltpara && (strlen(saltpara) <= 22)) | |
421 | { | |
422 | /* sprintf used because of portability requirements, the length | |
423 | ** is checked above, so it should not be too much of a concern | |
424 | */ | |
425 | sprintf(tbuf, "%02d", rounds); | |
426 | sprintf(salt, "$2a$%s$%s$", tbuf, saltpara); | |
427 | return salt; | |
428 | } | |
429 | printf("Invalid Salt, please use up to 22 random alphanumeric characters\n"); | |
430 | exit(1); | |
431 | ||
432 | /* NOT REACHED */ | |
433 | return NULL; | |
434 | } | |
435 | ||
436 | char * | |
437 | make_bf_salt(int rounds, int length) | |
438 | { | |
439 | static char salt[31]; | |
440 | char tbuf[3]; | |
441 | if(length > 22) | |
442 | { | |
443 | printf("BlowFish salt length too long\n"); | |
444 | exit(0); | |
445 | } | |
446 | sprintf(tbuf, "%02d", rounds); | |
447 | sprintf(salt, "$2a$%s$", tbuf); | |
448 | generate_random_salt(&salt[7], length); | |
449 | salt[length + 7] = '$'; | |
450 | salt[length + 8] = '\0'; | |
451 | return salt; | |
452 | } | |
453 | ||
454 | char * | |
455 | generate_poor_salt(char *salt, int length) | |
456 | { | |
457 | int i; | |
458 | srand(time(NULL)); | |
459 | for(i = 0; i < length; i++) | |
460 | { | |
461 | salt[i] = saltChars[rand() % 64]; | |
462 | } | |
463 | return (salt); | |
464 | } | |
465 | ||
466 | char * | |
467 | generate_random_salt(char *salt, int length) | |
468 | { | |
469 | char *buf; | |
470 | int fd, i; | |
471 | if((fd = open("/dev/random", O_RDONLY)) < 0) | |
472 | { | |
473 | return (generate_poor_salt(salt, length)); | |
474 | } | |
475 | buf = calloc(1, length); | |
476 | if(read(fd, buf, length) != length) | |
477 | { | |
478 | free(buf); | |
479 | return (generate_poor_salt(salt, length)); | |
480 | } | |
481 | ||
482 | for(i = 0; i < length; i++) | |
483 | { | |
484 | salt[i] = saltChars[abs(buf[i]) % 64]; | |
485 | } | |
486 | free(buf); | |
487 | return (salt); | |
212380e3 AC |
488 | } |
489 | ||
f1d07f6b JT |
490 | void |
491 | full_usage() | |
212380e3 | 492 | { |
f1d07f6b JT |
493 | printf("mkpasswd [-m|-d|-b|-e] [-l saltlength] [-r rounds] [-s salt] [-p plaintext]\n"); |
494 | printf("-x Generate a SHA256 password\n"); | |
495 | printf("-y Generate a SHA512 password\n"); | |
496 | printf("-m Generate an MD5 password\n"); | |
497 | printf("-d Generate a DES password\n"); | |
498 | printf("-b Generate a BlowFish password\n"); | |
499 | printf("-e Generate an Extended DES password\n"); | |
500 | printf("-l Specify a length for a random MD5 or BlowFish salt\n"); | |
501 | printf("-r Specify a number of rounds for a BlowFish or Extended DES password\n"); | |
502 | printf(" BlowFish: default 4, no more than 6 recommended\n"); | |
503 | printf(" Extended DES: default 25\n"); | |
504 | printf("-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for MD5,\n"); | |
505 | printf(" up to 22 for BlowFish, and 4 for Extended DES\n"); | |
506 | printf("-p Specify a plaintext password to use\n"); | |
507 | printf("Example: mkpasswd -m -s 3dr -p test\n"); | |
508 | exit(0); | |
212380e3 AC |
509 | } |
510 | ||
f1d07f6b JT |
511 | void |
512 | brief_usage() | |
212380e3 | 513 | { |
f1d07f6b JT |
514 | printf("mkpasswd - password hash generator\n"); |
515 | printf("Standard DES: mkpasswd [-d] [-s salt] [-p plaintext]\n"); | |
516 | printf("Extended DES: mkpasswd -e [-r rounds] [-s salt] [-p plaintext]\n"); | |
517 | printf(" MD5: mkpasswd -m [-l saltlength] [-s salt] [-p plaintext]\n"); | |
518 | printf(" BlowFish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n"); | |
519 | printf(" [-p plaintext]\n"); | |
520 | printf("Use -h for full usage\n"); | |
521 | exit(0); | |
212380e3 | 522 | } |