]> jfr.im git - irc/rqf/shadowircd.git/blob - tools/mkpasswd.c
ed18c107f9073fb1640f85a59a4b300aef112672
[irc/rqf/shadowircd.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 "ratbox_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 extern char *optarg;
58
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)
70 {
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;
92 }
93 #endif
94
95
96 int
97 main(int argc, char *argv[])
98 {
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
165 if(flag & FLAG_BLOWFISH)
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 }
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 }
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 }
212 else if (flag & FLAG_DES)
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 }
231 else
232 {
233 if(length == 0)
234 length = 8;
235 if(flag & FLAG_SALT)
236 salt = make_md5_salt_para(saltpara);
237 else
238 salt = make_md5_salt(length);
239 }
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;
253 }
254
255 static char *
256 make_des_salt()
257 {
258 static char salt[3];
259 generate_random_salt(salt, 2);
260 salt[2] = '\0';
261 return salt;
262 }
263
264 char *
265 int_to_base64(int value)
266 {
267 static char buf[5];
268 int i;
269
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;
280 }
281
282 char *
283 make_ext_salt(int rounds)
284 {
285 static char salt[10];
286
287 sprintf(salt, "_%s", int_to_base64(rounds));
288 generate_random_salt(&salt[5], 4);
289 salt[9] = '\0';
290 return salt;
291 }
292
293 char *
294 make_ext_salt_para(int rounds, char *saltpara)
295 {
296 static char salt[10];
297
298 sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara);
299 return salt;
300 }
301
302 char *
303 make_md5_salt_para(char *saltpara)
304 {
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;
319 }
320
321 char *
322 make_md5_salt(int length)
323 {
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;
337 }
338
339 char *
340 make_sha256_salt_para(char *saltpara)
341 {
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;
356 }
357
358 char *
359 make_sha512_salt_para(char *saltpara)
360 {
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;
375 }
376
377
378 char *
379 make_sha256_salt(int length)
380 {
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);
487 }
488
489 void
490 full_usage()
491 {
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);
508 }
509
510 void
511 brief_usage()
512 {
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);
521 }