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