]> jfr.im git - solanum.git/blob - tools/mkpasswd.c
commio: further win32 fixes
[solanum.git] / tools / mkpasswd.c
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 **
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>
19 #include "rb_lib.h"
20 #ifndef __MINGW32__
21 #include <pwd.h>
22 #endif
23
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
29 #define FLAG_BLOWFISH 0x00000020
30 #define FLAG_ROUNDS 0x00000040
31 #define FLAG_EXT 0x00000080
32 #define FLAG_SHA256 0x00000100
33 #define FLAG_SHA512 0x00000200
34
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 *);
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 *);
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
54 static char saltChars[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
55 /* 0 .. 63, ascii - 64 */
56
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)
67 {
68 int c;
69 int i = 0;
70
71 memset(getpassbuf, 0, sizeof(getpassbuf));
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;
89 }
90 #endif
91
92
93 int
94 main(int argc, char *argv[])
95 {
96 char *plaintext = NULL;
97 int c;
98 char *saltpara = NULL;
99 char *salt;
100 char *hashed;
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
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)
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 }
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 }
210 else if (flag & FLAG_DES)
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 }
229 else
230 {
231 if(length == 0)
232 length = 16;
233 if(flag & FLAG_SALT)
234 salt = make_sha512_salt_para(saltpara);
235 else
236 salt = make_sha512_salt(length);
237 }
238
239 if(flag & FLAG_PASS)
240 {
241 if(!plaintext)
242 {
243 fprintf(stderr, "Please enter a valid password\n");
244 return 1;
245 }
246
247 hashed = rb_crypt(plaintext, salt);
248 }
249 else
250 {
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 }
259 }
260
261 printf("%s\n", hashed);
262 return 0;
263 }
264
265 static char *
266 make_des_salt()
267 {
268 static char salt[3];
269 generate_random_salt(salt, 2);
270 salt[2] = '\0';
271 return salt;
272 }
273
274 char *
275 int_to_base64(int value)
276 {
277 static char buf[5];
278 int i;
279
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;
290 }
291
292 char *
293 make_ext_salt(int rounds)
294 {
295 static char salt[10];
296
297 sprintf(salt, "_%s", int_to_base64(rounds));
298 generate_random_salt(&salt[5], 4);
299 salt[9] = '\0';
300 return salt;
301 }
302
303 char *
304 make_ext_salt_para(int rounds, char *saltpara)
305 {
306 static char salt[10];
307
308 sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara);
309 return salt;
310 }
311
312 char *
313 make_md5_salt_para(char *saltpara)
314 {
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;
329 }
330
331 char *
332 make_md5_salt(int length)
333 {
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;
347 }
348
349 char *
350 make_sha256_salt_para(char *saltpara)
351 {
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;
366 }
367
368 char *
369 make_sha512_salt_para(char *saltpara)
370 {
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;
385 }
386
387
388 char *
389 make_sha256_salt(int length)
390 {
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 {
452 printf("Blowfish salt length too long\n");
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);
497 }
498
499 void
500 full_usage()
501 {
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");
507 printf("-b Generate a Blowfish password\n");
508 printf("-e Generate an Extended DES password\n");
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");
512 printf(" Extended DES: default 25\n");
513 printf("-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for MD5,\n");
514 printf(" up to 22 for Blowfish, and 4 for Extended DES\n");
515 printf("-p Specify a plaintext password to use\n");
516 printf("Example: mkpasswd -m -s 3dr -p test\n");
517 exit(0);
518 }
519
520 void
521 brief_usage()
522 {
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");
527 printf(" Blowfish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
528 printf(" [-p plaintext]\n");
529 printf("Use -h for full usage\n");
530 exit(0);
531 }