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