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