]> jfr.im git - solanum.git/blame - tools/mkpasswd.c
Add .travis.yml
[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
f1d07f6b
JT
58#ifdef __MINGW32__
59#include <conio.h>
60#ifdef PASS_MAX
61#undef PASS_MAX
62#endif
63#define PASS_MAX 256
64static char getpassbuf[PASS_MAX + 1];
65
66static char *
67getpass(const char *prompt)
212380e3 68{
f1d07f6b
JT
69 int c;
70 int i = 0;
71
29c92cf9 72 memset(getpassbuf, 0, sizeof(getpassbuf));
f1d07f6b
JT
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;
212380e3 90}
f1d07f6b
JT
91#endif
92
212380e3 93
f1d07f6b
JT
94int
95main(int argc, char *argv[])
212380e3 96{
f1d07f6b
JT
97 char *plaintext = NULL;
98 int c;
99 char *saltpara = NULL;
100 char *salt;
011e38be 101 char *hashed;
f1d07f6b
JT
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
7600b65f
EM
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)
f1d07f6b
JT
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 }
f1d07f6b
JT
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 }
920cb1dc 211 else if (flag & FLAG_DES)
f1d07f6b
JT
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 }
920cb1dc
AC
230 else
231 {
232 if(length == 0)
7600b65f 233 length = 16;
920cb1dc 234 if(flag & FLAG_SALT)
7600b65f 235 salt = make_sha512_salt_para(saltpara);
920cb1dc 236 else
7600b65f 237 salt = make_sha512_salt(length);
920cb1dc 238 }
f1d07f6b
JT
239
240 if(flag & FLAG_PASS)
241 {
242 if(!plaintext)
011e38be
AI
243 {
244 fprintf(stderr, "Please enter a valid password\n");
245 return 1;
246 }
247
248 hashed = rb_crypt(plaintext, salt);
f1d07f6b
JT
249 }
250 else
251 {
011e38be
AI
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 }
f1d07f6b
JT
260 }
261
011e38be 262 printf("%s\n", hashed);
f1d07f6b 263 return 0;
212380e3
AC
264}
265
f1d07f6b
JT
266static char *
267make_des_salt()
212380e3 268{
f1d07f6b
JT
269 static char salt[3];
270 generate_random_salt(salt, 2);
271 salt[2] = '\0';
272 return salt;
212380e3
AC
273}
274
f1d07f6b
JT
275char *
276int_to_base64(int value)
212380e3 277{
f1d07f6b
JT
278 static char buf[5];
279 int i;
212380e3 280
f1d07f6b
JT
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;
212380e3
AC
291}
292
f1d07f6b
JT
293char *
294make_ext_salt(int rounds)
212380e3 295{
f1d07f6b 296 static char salt[10];
212380e3 297
f1d07f6b
JT
298 sprintf(salt, "_%s", int_to_base64(rounds));
299 generate_random_salt(&salt[5], 4);
300 salt[9] = '\0';
301 return salt;
212380e3
AC
302}
303
f1d07f6b
JT
304char *
305make_ext_salt_para(int rounds, char *saltpara)
212380e3 306{
f1d07f6b
JT
307 static char salt[10];
308
309 sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara);
310 return salt;
212380e3 311}
f1d07f6b
JT
312
313char *
314make_md5_salt_para(char *saltpara)
212380e3 315{
f1d07f6b
JT
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;
212380e3
AC
330}
331
f1d07f6b
JT
332char *
333make_md5_salt(int length)
212380e3 334{
f1d07f6b
JT
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;
212380e3
AC
348}
349
f1d07f6b
JT
350char *
351make_sha256_salt_para(char *saltpara)
212380e3 352{
f1d07f6b
JT
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;
212380e3
AC
367}
368
f1d07f6b
JT
369char *
370make_sha512_salt_para(char *saltpara)
212380e3 371{
f1d07f6b
JT
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;
212380e3
AC
386}
387
f1d07f6b
JT
388
389char *
390make_sha256_salt(int length)
212380e3 391{
f1d07f6b
JT
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
407char *
408make_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
425char *
426make_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
446char *
447make_bf_salt(int rounds, int length)
448{
449 static char salt[31];
450 char tbuf[3];
451 if(length > 22)
452 {
69b2e745 453 printf("Blowfish salt length too long\n");
f1d07f6b
JT
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
464char *
465generate_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
476char *
477generate_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);
212380e3
AC
498}
499
f1d07f6b
JT
500void
501full_usage()
212380e3 502{
f1d07f6b
JT
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");
69b2e745 508 printf("-b Generate a Blowfish password\n");
f1d07f6b 509 printf("-e Generate an Extended DES password\n");
69b2e745
LS
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");
f1d07f6b
JT
513 printf(" Extended DES: default 25\n");
514 printf("-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for MD5,\n");
69b2e745 515 printf(" up to 22 for Blowfish, and 4 for Extended DES\n");
f1d07f6b
JT
516 printf("-p Specify a plaintext password to use\n");
517 printf("Example: mkpasswd -m -s 3dr -p test\n");
518 exit(0);
212380e3
AC
519}
520
f1d07f6b
JT
521void
522brief_usage()
212380e3 523{
f1d07f6b
JT
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");
69b2e745 528 printf(" Blowfish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
f1d07f6b
JT
529 printf(" [-p plaintext]\n");
530 printf("Use -h for full usage\n");
531 exit(0);
212380e3 532}