More RCS keyword removal...
[seven-1.x.git] / tools / mkpasswd.c
blob8358b617d5d4c9862d360aeb4a73f9dcfcd6db13
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>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <time.h>
16 #include <unistd.h>
17 #include <fcntl.h>
19 #define FLAG_MD5 0x00000001
20 #define FLAG_DES 0x00000002
21 #define FLAG_SALT 0x00000004
22 #define FLAG_PASS 0x00000008
23 #define FLAG_LENGTH 0x00000010
24 #define FLAG_BLOWFISH 0x00000020
25 #define FLAG_ROUNDS 0x00000040
26 #define FLAG_EXT 0x00000080
28 extern char *getpass();
29 extern char *crypt();
31 static char *make_des_salt(void);
32 static char *make_ext_salt(int);
33 static char *make_ext_salt_para(int, char *);
34 static char *make_md5_salt(int);
35 static char *make_md5_salt_para(char *);
36 static char *make_bf_salt(int, int);
37 static char *make_bf_salt_para(int, char *);
38 static char *int_to_base64(int);
39 static char *generate_random_salt(char *, int);
40 static char *generate_poor_salt(char *, int);
42 static void full_usage(void);
43 static void brief_usage(void);
45 static char saltChars[] =
46 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
47 /* 0 .. 63, ascii - 64 */
49 extern char *optarg;
51 int main(int argc, char *argv[])
53 char *plaintext = NULL;
54 int c;
55 char *saltpara = NULL;
56 char *salt;
57 int flag = 0;
58 int length = 0; /* Not Set */
59 int rounds = 0; /* Not set, since extended DES needs 25 and blowfish needs
60 ** 4 by default, a side effect of this being the encryption
61 ** type parameter must be specified before the rounds
62 ** parameter.
65 while( (c=getopt(argc, argv, "mdber:h?l:s:p:")) != -1)
67 switch(c)
69 case 'm':
70 flag |= FLAG_MD5;
71 break;
72 case 'd':
73 flag |= FLAG_DES;
74 break;
75 case 'b':
76 flag |= FLAG_BLOWFISH;
77 rounds = 4;
78 break;
79 case 'e':
80 flag |= FLAG_EXT;
81 rounds = 25;
82 break;
83 case 'l':
84 flag |= FLAG_LENGTH;
85 length = atoi(optarg);
86 break;
87 case 'r':
88 flag |= FLAG_ROUNDS;
89 rounds = atoi(optarg);
90 break;
91 case 's':
92 flag |= FLAG_SALT;
93 saltpara = optarg;
94 break;
95 case 'p':
96 flag |= FLAG_PASS;
97 plaintext = optarg;
98 break;
99 case 'h':
100 full_usage();
101 /* NOT REACHED */
102 break;
103 case '?':
104 brief_usage();
105 /* NOT REACHED */
106 break;
107 default:
108 printf("Invalid Option: -%c\n", c);
109 break;
113 if (flag & FLAG_MD5)
115 if (length == 0)
116 length = 8;
117 if (flag & FLAG_SALT)
118 salt = make_md5_salt_para(saltpara);
119 else
120 salt = make_md5_salt(length);
122 else if (flag & FLAG_BLOWFISH)
124 if (length == 0)
125 length = 22;
126 if (flag & FLAG_SALT)
127 salt = make_bf_salt_para(rounds, saltpara);
128 else
129 salt = make_bf_salt(rounds, length);
131 else if (flag & FLAG_EXT)
133 /* XXX - rounds needs to be done */
134 if (flag & FLAG_SALT)
136 if ((strlen(saltpara) == 4))
138 salt = make_ext_salt_para(rounds, saltpara);
140 else
142 printf("Invalid salt, please enter 4 alphanumeric characters\n");
143 exit(1);
146 else
148 salt = make_ext_salt(rounds);
151 else
153 if (flag & FLAG_SALT)
155 if ((strlen(saltpara) == 2))
157 salt = saltpara;
159 else
161 printf("Invalid salt, please enter 2 alphanumeric characters\n");
162 exit(1);
165 else
167 salt = make_des_salt();
171 if (flag & FLAG_PASS)
173 if (!plaintext)
174 printf("Please enter a valid password\n");
176 else
178 plaintext = getpass("plaintext: ");
181 printf("%s\n", crypt(plaintext, salt));
182 return 0;
185 static char *make_des_salt()
187 static char salt[3];
188 generate_random_salt(salt, 2);
189 salt[2] = '\0';
190 return salt;
193 char *int_to_base64(int value)
195 static char buf[5];
196 int i;
198 for (i = 0; i < 4; i++)
200 buf[i] = saltChars[value & 63];
201 value >>= 6; /* Right shifting 6 places is the same as dividing by 64 */
204 buf[i] = '\0'; /* not REALLY needed as it's static, and thus initialized
205 ** to \0.
207 return buf;
210 char *make_ext_salt(int rounds)
212 static char salt[10];
214 sprintf(salt, "_%s", int_to_base64(rounds));
215 generate_random_salt(&salt[5], 4);
216 salt[9] = '\0';
217 return salt;
220 char *make_ext_salt_para(int rounds, char *saltpara)
222 static char salt[10];
224 sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara);
225 return salt;
228 char *make_md5_salt_para(char *saltpara)
230 static char salt[21];
231 if (saltpara && (strlen(saltpara) <= 16))
233 /* sprintf used because of portability requirements, the length
234 ** is checked above, so it should not be too much of a concern
236 sprintf(salt, "$1$%s$", saltpara);
237 return salt;
239 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
240 exit(1);
242 /* NOT REACHED */
243 return NULL;
246 char *make_md5_salt(int length)
248 static char salt[21];
249 if (length > 16)
251 printf("MD5 salt length too long\n");
252 exit(0);
254 salt[0] = '$';
255 salt[1] = '1';
256 salt[2] = '$';
257 generate_random_salt(&salt[3], length);
258 salt[length+3] = '$';
259 salt[length+4] = '\0';
260 return salt;
263 char *make_bf_salt_para(int rounds, char *saltpara)
265 static char salt[31];
266 char tbuf[3];
267 if (saltpara && (strlen(saltpara) <= 22))
269 /* sprintf used because of portability requirements, the length
270 ** is checked above, so it should not be too much of a concern
272 sprintf(tbuf, "%02d", rounds);
273 sprintf(salt, "$2a$%s$%s$", tbuf, saltpara);
274 return salt;
276 printf("Invalid Salt, please use up to 22 random alphanumeric characters\n");
277 exit(1);
279 /* NOT REACHED */
280 return NULL;
283 char *make_bf_salt(int rounds, int length)
285 static char salt[31];
286 char tbuf[3];
287 if (length > 22)
289 printf("BlowFish salt length too long\n");
290 exit(0);
292 sprintf(tbuf, "%02d", rounds);
293 sprintf(salt, "$2a$%s$", tbuf);
294 generate_random_salt(&salt[7], length);
295 salt[length+7] = '$';
296 salt[length+8] = '\0';
297 return salt;
300 char *generate_poor_salt(char *salt, int length)
302 int i;
303 srandom(time(NULL));
304 for(i = 0; i < length; i++)
306 salt[i] = saltChars[random() % 64];
308 return(salt);
311 char *generate_random_salt(char *salt, int length)
313 char *buf;
314 int fd, i;
315 if((fd = open("/dev/random", O_RDONLY)) < 0)
317 return(generate_poor_salt(salt, length));
319 buf = calloc(1, length);
320 if(read(fd, buf, length) != length)
322 free(buf);
323 return(generate_poor_salt(salt, length));
326 for(i = 0; i < length; i++)
328 salt[i] = saltChars[abs(buf[i]) % 64];
330 free(buf);
331 return(salt);
334 void full_usage()
336 printf("mkpasswd [-m|-d|-b|-e] [-l saltlength] [-r rounds] [-s salt] [-p plaintext]\n");
337 printf("-m Generate an MD5 password\n");
338 printf("-d Generate a DES password\n");
339 printf("-b Generate a BlowFish password\n");
340 printf("-e Generate an Extended DES password\n");
341 printf("-l Specify a length for a random MD5 or BlowFish salt\n");
342 printf("-r Specify a number of rounds for a BlowFish or Extended DES password\n");
343 printf(" BlowFish: default 4, no more than 6 recommended\n");
344 printf(" Extended DES: default 25\n");
345 printf("-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for MD5,\n");
346 printf(" up to 22 for BlowFish, and 4 for Extended DES\n");
347 printf("-p Specify a plaintext password to use\n");
348 printf("Example: mkpasswd -m -s 3dr -p test\n");
349 exit(0);
352 void brief_usage()
354 printf("mkpasswd - password hash generator\n");
355 printf("Standard DES: mkpasswd [-d] [-s salt] [-p plaintext]\n");
356 printf("Extended DES: mkpasswd -e [-r rounds] [-s salt] [-p plaintext]\n");
357 printf(" MD5: mkpasswd -m [-l saltlength] [-s salt] [-p plaintext]\n");
358 printf(" BlowFish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
359 printf(" [-p plaintext]\n");
360 printf("Use -h for full usage\n");
361 exit(0);