]> jfr.im git - irc/rqf/shadowircd.git/blame - tools/mkpasswd.c
Updating File.
[irc/rqf/shadowircd.git] / tools / mkpasswd.c
CommitLineData
212380e3 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**
00ba96a1 12** $Id: mkpasswd.c 26439 2009-02-01 15:27:24Z jilles $
212380e3 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>
00ba96a1
JT
20#include "ratbox_lib.h"
21#ifndef __MINGW32__
22#include <pwd.h>
23#endif
212380e3 24
00ba96a1
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
00ba96a1
JT
31#define FLAG_ROUNDS 0x00000040
32#define FLAG_EXT 0x00000080
33#define FLAG_SHA256 0x00000100
34#define FLAG_SHA512 0x00000200
212380e3 35
212380e3 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 *);
00ba96a1
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 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
00ba96a1 55static char saltChars[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
212380e3 56 /* 0 .. 63, ascii - 64 */
57
58extern char *optarg;
59
00ba96a1
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{
00ba96a1
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}
00ba96a1
JT
94#endif
95
212380e3 96
00ba96a1
JT
97int
98main(int argc, char *argv[])
212380e3 99{
00ba96a1
JT
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;
212380e3 254}
255
00ba96a1
JT
256static char *
257make_des_salt()
212380e3 258{
00ba96a1
JT
259 static char salt[3];
260 generate_random_salt(salt, 2);
261 salt[2] = '\0';
262 return salt;
212380e3 263}
264
00ba96a1
JT
265char *
266int_to_base64(int value)
212380e3 267{
00ba96a1
JT
268 static char buf[5];
269 int i;
212380e3 270
00ba96a1
JT
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;
212380e3 281}
282
00ba96a1
JT
283char *
284make_ext_salt(int rounds)
212380e3 285{
00ba96a1 286 static char salt[10];
212380e3 287
00ba96a1
JT
288 sprintf(salt, "_%s", int_to_base64(rounds));
289 generate_random_salt(&salt[5], 4);
290 salt[9] = '\0';
291 return salt;
212380e3 292}
293
00ba96a1
JT
294char *
295make_ext_salt_para(int rounds, char *saltpara)
212380e3 296{
00ba96a1
JT
297 static char salt[10];
298
299 sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara);
300 return salt;
212380e3 301}
00ba96a1
JT
302
303char *
304make_md5_salt_para(char *saltpara)
212380e3 305{
00ba96a1
JT
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;
212380e3 320}
321
00ba96a1
JT
322char *
323make_md5_salt(int length)
212380e3 324{
00ba96a1
JT
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;
212380e3 338}
339
00ba96a1
JT
340char *
341make_sha256_salt_para(char *saltpara)
212380e3 342{
00ba96a1
JT
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;
212380e3 357}
358
00ba96a1
JT
359char *
360make_sha512_salt_para(char *saltpara)
212380e3 361{
00ba96a1
JT
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;
212380e3 376}
377
00ba96a1
JT
378
379char *
380make_sha256_salt(int length)
212380e3 381{
00ba96a1
JT
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
397char *
398make_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
415char *
416make_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
436char *
437make_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
454char *
455generate_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
466char *
467generate_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);
212380e3 488}
489
00ba96a1
JT
490void
491full_usage()
212380e3 492{
00ba96a1
JT
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);
212380e3 509}
510
00ba96a1
JT
511void
512brief_usage()
212380e3 513{
00ba96a1
JT
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);
212380e3 522}