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