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