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