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