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