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.
5 ** md5 patch by W. Campbell <wcampbel@botbay.net>
6 ** Modernization, getopt, etc for the Hybrid IRCD team
9 ** /dev/random for salt generation added by
10 ** Aaron Sethman <androsyn@ratbox.org>
12 ** $Id: mkpasswd.c 26 2006-09-20 18:02:06Z spb $
21 #define FLAG_MD5 0x00000001
22 #define FLAG_DES 0x00000002
23 #define FLAG_SALT 0x00000004
24 #define FLAG_PASS 0x00000008
25 #define FLAG_LENGTH 0x00000010
26 #define FLAG_BLOWFISH 0x00000020
27 #define FLAG_ROUNDS 0x00000040
28 #define FLAG_EXT 0x00000080
30 extern char *getpass();
33 static char *make_des_salt(void);
34 static char *make_ext_salt(int);
35 static char *make_ext_salt_para(int, char *);
36 static char *make_md5_salt(int);
37 static char *make_md5_salt_para(char *);
38 static char *make_bf_salt(int, int);
39 static char *make_bf_salt_para(int, char *);
40 static char *int_to_base64(int);
41 static char *generate_random_salt(char *, int);
42 static char *generate_poor_salt(char *, int);
44 static void full_usage(void);
45 static void brief_usage(void);
47 static char saltChars
[] =
48 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
49 /* 0 .. 63, ascii - 64 */
53 int main(int argc
, char *argv
[])
55 char *plaintext
= NULL
;
57 char *saltpara
= NULL
;
60 int length
= 0; /* Not Set */
61 int rounds
= 0; /* Not set, since extended DES needs 25 and blowfish needs
62 ** 4 by default, a side effect of this being the encryption
63 ** type parameter must be specified before the rounds
67 while( (c
=getopt(argc
, argv
, "mdber:h?l:s:p:")) != -1)
78 flag
|= FLAG_BLOWFISH
;
87 length
= atoi(optarg
);
91 rounds
= atoi(optarg
);
110 printf("Invalid Option: -%c\n", c
);
119 if (flag
& FLAG_SALT
)
120 salt
= make_md5_salt_para(saltpara
);
122 salt
= make_md5_salt(length
);
124 else if (flag
& FLAG_BLOWFISH
)
128 if (flag
& FLAG_SALT
)
129 salt
= make_bf_salt_para(rounds
, saltpara
);
131 salt
= make_bf_salt(rounds
, length
);
133 else if (flag
& FLAG_EXT
)
135 /* XXX - rounds needs to be done */
136 if (flag
& FLAG_SALT
)
138 if ((strlen(saltpara
) == 4))
140 salt
= make_ext_salt_para(rounds
, saltpara
);
144 printf("Invalid salt, please enter 4 alphanumeric characters\n");
150 salt
= make_ext_salt(rounds
);
155 if (flag
& FLAG_SALT
)
157 if ((strlen(saltpara
) == 2))
163 printf("Invalid salt, please enter 2 alphanumeric characters\n");
169 salt
= make_des_salt();
173 if (flag
& FLAG_PASS
)
176 printf("Please enter a valid password\n");
180 plaintext
= getpass("plaintext: ");
183 printf("%s\n", crypt(plaintext
, salt
));
187 static char *make_des_salt()
190 generate_random_salt(salt
, 2);
195 char *int_to_base64(int value
)
200 for (i
= 0; i
< 4; i
++)
202 buf
[i
] = saltChars
[value
& 63];
203 value
>>= 6; /* Right shifting 6 places is the same as dividing by 64 */
206 buf
[i
] = '\0'; /* not REALLY needed as it's static, and thus initialized
212 char *make_ext_salt(int rounds
)
214 static char salt
[10];
216 sprintf(salt
, "_%s", int_to_base64(rounds
));
217 generate_random_salt(&salt
[5], 4);
222 char *make_ext_salt_para(int rounds
, char *saltpara
)
224 static char salt
[10];
226 sprintf(salt
, "_%s%s", int_to_base64(rounds
), saltpara
);
230 char *make_md5_salt_para(char *saltpara
)
232 static char salt
[21];
233 if (saltpara
&& (strlen(saltpara
) <= 16))
235 /* sprintf used because of portability requirements, the length
236 ** is checked above, so it should not be too much of a concern
238 sprintf(salt
, "$1$%s$", saltpara
);
241 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
248 char *make_md5_salt(int length
)
250 static char salt
[21];
253 printf("MD5 salt length too long\n");
259 generate_random_salt(&salt
[3], length
);
260 salt
[length
+3] = '$';
261 salt
[length
+4] = '\0';
265 char *make_bf_salt_para(int rounds
, char *saltpara
)
267 static char salt
[31];
269 if (saltpara
&& (strlen(saltpara
) <= 22))
271 /* sprintf used because of portability requirements, the length
272 ** is checked above, so it should not be too much of a concern
274 sprintf(tbuf
, "%02d", rounds
);
275 sprintf(salt
, "$2a$%s$%s$", tbuf
, saltpara
);
278 printf("Invalid Salt, please use up to 22 random alphanumeric characters\n");
285 char *make_bf_salt(int rounds
, int length
)
287 static char salt
[31];
291 printf("BlowFish salt length too long\n");
294 sprintf(tbuf
, "%02d", rounds
);
295 sprintf(salt
, "$2a$%s$", tbuf
);
296 generate_random_salt(&salt
[7], length
);
297 salt
[length
+7] = '$';
298 salt
[length
+8] = '\0';
302 char *generate_poor_salt(char *salt
, int length
)
306 for(i
= 0; i
< length
; i
++)
308 salt
[i
] = saltChars
[random() % 64];
313 char *generate_random_salt(char *salt
, int length
)
317 if((fd
= open("/dev/random", O_RDONLY
)) < 0)
319 return(generate_poor_salt(salt
, length
));
321 buf
= calloc(1, length
);
322 if(read(fd
, buf
, length
) != length
)
325 return(generate_poor_salt(salt
, length
));
328 for(i
= 0; i
< length
; i
++)
330 salt
[i
] = saltChars
[abs(buf
[i
]) % 64];
338 printf("mkpasswd [-m|-d|-b|-e] [-l saltlength] [-r rounds] [-s salt] [-p plaintext]\n");
339 printf("-m Generate an MD5 password\n");
340 printf("-d Generate a DES password\n");
341 printf("-b Generate a BlowFish password\n");
342 printf("-e Generate an Extended DES password\n");
343 printf("-l Specify a length for a random MD5 or BlowFish salt\n");
344 printf("-r Specify a number of rounds for a BlowFish or Extended DES password\n");
345 printf(" BlowFish: default 4, no more than 6 recommended\n");
346 printf(" Extended DES: default 25\n");
347 printf("-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for MD5,\n");
348 printf(" up to 22 for BlowFish, and 4 for Extended DES\n");
349 printf("-p Specify a plaintext password to use\n");
350 printf("Example: mkpasswd -m -s 3dr -p test\n");
356 printf("mkpasswd - password hash generator\n");
357 printf("Standard DES: mkpasswd [-d] [-s salt] [-p plaintext]\n");
358 printf("Extended DES: mkpasswd -e [-r rounds] [-s salt] [-p plaintext]\n");
359 printf(" MD5: mkpasswd -m [-l saltlength] [-s salt] [-p plaintext]\n");
360 printf(" BlowFish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
361 printf(" [-p plaintext]\n");
362 printf("Use -h for full usage\n");