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