summaryrefslogtreecommitdiff
path: root/tools/mkpasswd.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mkpasswd.c')
-rw-r--r--tools/mkpasswd.c533
1 files changed, 533 insertions, 0 deletions
diff --git a/tools/mkpasswd.c b/tools/mkpasswd.c
new file mode 100644
index 0000000..c4234d5
--- /dev/null
+++ b/tools/mkpasswd.c
@@ -0,0 +1,533 @@
+/* simple password generator by Nelson Minar (minar@reed.edu)
+** copyright 1991, all rights reserved.
+** You can use this code as long as my name stays with it.
+**
+** md5 patch by W. Campbell <wcampbel@botbay.net>
+** Modernization, getopt, etc for the Hybrid IRCD team
+** by W. Campbell
+**
+** /dev/random for salt generation added by
+** Aaron Sethman <androsyn@ratbox.org>
+**
+** $Id$
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define FLAG_MD5 0x00000001
+#define FLAG_DES 0x00000002
+#define FLAG_SALT 0x00000004
+#define FLAG_PASS 0x00000008
+#define FLAG_LENGTH 0x00000010
+#define FLAG_BLOWFISH 0x00000020
+#define FLAG_ROUNDS 0x00000040
+#define FLAG_EXT 0x00000080
+#define FLAG_RAW 0x00000100
+#define FLAG_SHA256 0x00000200
+#define FLAG_SHA512 0x00000400
+
+
+extern char *crypt();
+
+
+static char *make_sha256_salt(int);
+static char *make_sha256_salt_para(const char *);
+static char *make_sha512_salt(int);
+static char *make_sha512_salt_para(const char *);
+static char *make_des_salt(void);
+static char *make_ext_salt(int);
+static char *make_ext_salt_para(int, const char *);
+static char *make_md5_salt(int);
+static char *make_md5_salt_para(const char *);
+static char *make_bf_salt(int, int);
+static char *make_bf_salt_para(int, const char *);
+static char *int_to_base64(int);
+static char *generate_random_salt(char *, int);
+static char *generate_poor_salt(char *, int);
+static void full_usage(void);
+static void brief_usage(void);
+
+static const char saltChars[] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ /* 0 .. 63, ascii - 64 */
+
+int
+main(int argc, char *argv[])
+{
+ const char *plaintext = NULL;
+ int c;
+ char *saltpara = NULL;
+ char *salt;
+ int flag = 0;
+ int length = 0; /* Not Set */
+ int rounds = 0; /* Not set, since extended DES needs 25 and blowfish needs
+ ** 4 by default, a side effect of this being the encryption
+ ** type parameter must be specified before the rounds
+ ** parameter.
+ */
+
+ while ((c = getopt(argc, argv, "56mdber:h?l:s:p:R:")) != -1)
+ {
+ switch (c)
+ {
+ case '5':
+ flag |= FLAG_SHA256;
+ break;
+ case '6':
+ flag |= FLAG_SHA512;
+ break;
+ case 'm':
+ flag |= FLAG_MD5;
+ break;
+ case 'd':
+ flag |= FLAG_DES;
+ break;
+ case 'b':
+ flag |= FLAG_BLOWFISH;
+ rounds = 4;
+ break;
+ case 'e':
+ flag |= FLAG_EXT;
+ rounds = 25;
+ break;
+ case 'l':
+ flag |= FLAG_LENGTH;
+ length = atoi(optarg);
+ break;
+ case 'r':
+ flag |= FLAG_ROUNDS;
+ rounds = atoi(optarg);
+ break;
+ case 's':
+ flag |= FLAG_SALT;
+ saltpara = optarg;
+ break;
+ case 'p':
+ flag |= FLAG_PASS;
+ plaintext = optarg;
+ break;
+ case 'R':
+ flag |= FLAG_RAW;
+ saltpara = optarg;
+ break;
+ case 'h':
+ full_usage();
+ /* NOT REACHED */
+ break;
+ case '?':
+ brief_usage();
+ /* NOT REACHED */
+ break;
+ default:
+ printf("Invalid Option: -%c\n", c);
+ break;
+ }
+ }
+
+ if (flag & FLAG_MD5)
+ {
+ if (length == 0)
+ length = 8;
+ if (flag & FLAG_SALT)
+ salt = make_md5_salt_para(saltpara);
+ else
+ salt = make_md5_salt(length);
+ }
+ else if (flag & FLAG_SHA256)
+ {
+ if (length == 0)
+ length = 16;
+ if (flag & FLAG_SALT)
+ salt = make_sha256_salt_para(saltpara);
+ else
+ salt = make_sha256_salt(length);
+ }
+ else if (flag & FLAG_SHA512)
+ {
+ if (length == 0)
+ length = 16;
+ if (flag & FLAG_SALT)
+ salt = make_sha512_salt_para(saltpara);
+ else
+ salt = make_sha512_salt(length);
+ }
+ else if (flag & FLAG_BLOWFISH)
+ {
+ if (length == 0)
+ length = 22;
+ if (flag & FLAG_SALT)
+ salt = make_bf_salt_para(rounds, saltpara);
+ else
+ salt = make_bf_salt(rounds, length);
+ }
+ else if (flag & FLAG_EXT)
+ {
+ /* XXX - rounds needs to be done */
+ if (flag & FLAG_SALT)
+ {
+ if ((strlen(saltpara) == 4))
+ {
+ salt = make_ext_salt_para(rounds, saltpara);
+ }
+ else
+ {
+ printf("Invalid salt, please enter 4 alphanumeric characters\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ salt = make_ext_salt(rounds);
+ }
+ }
+ else if (flag & FLAG_RAW)
+ {
+ salt = saltpara;
+ }
+ else /* Default to DES */
+ {
+ if (flag & FLAG_SALT)
+ {
+ if ((strlen(saltpara) == 2))
+ {
+ salt = saltpara;
+ }
+ else
+ {
+ printf("Invalid salt, please enter 2 alphanumeric characters\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ salt = make_des_salt();
+ }
+ }
+
+ if (flag & FLAG_PASS)
+ {
+ if (!plaintext)
+ printf("Please enter a valid password\n");
+ }
+ else
+ plaintext = getpass("plaintext: ");
+
+ printf("%s\n", crypt(plaintext, salt));
+ return 0;
+}
+
+static char *
+make_des_salt(void)
+{
+ static char salt[3];
+
+ generate_random_salt(salt, 2);
+ salt[2] = '\0';
+ return salt;
+}
+
+static char *
+int_to_base64(int value)
+{
+ static char buf[5];
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ buf[i] = saltChars[value & 63];
+ value >>= 6; /* Right shifting 6 places is the same as dividing by 64 */
+ }
+
+ buf[i] = '\0'; /* not REALLY needed as it's static, and thus initialized
+ ** to \0.
+ */
+ return buf;
+}
+
+static char *
+make_ext_salt(int rounds)
+{
+ static char salt[10];
+
+ sprintf(salt, "_%s", int_to_base64(rounds));
+ generate_random_salt(&salt[5], 4);
+ salt[9] = '\0';
+
+ return salt;
+}
+
+static char *
+make_ext_salt_para(int rounds, const char *saltpara)
+{
+ static char salt[10];
+
+ sprintf(salt, "_%s%s", int_to_base64(rounds), saltpara);
+ return salt;
+}
+
+static char *
+make_sha256_salt_para(const char *saltpara)
+{
+ static char salt[21];
+
+ if (saltpara && (strlen(saltpara) <= 16))
+ {
+ /*
+ * sprintf used because of portability requirements, the length
+ * is checked above, so it should not be too much of a concern
+ */
+ sprintf(salt, "$5$%s$", saltpara);
+ return salt;
+ }
+
+ printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
+ exit(1);
+
+ /* NOT REACHED */
+ return NULL;
+}
+
+static char *
+make_sha256_salt(int length)
+{
+ static char salt[21];
+
+ if (length > 16)
+ {
+ printf("SHA256 salt length too long\n");
+ exit(0);
+ }
+
+ salt[0] = '$';
+ salt[1] = '5';
+ salt[2] = '$';
+
+ generate_random_salt(&salt[3], length);
+
+ salt[length + 3] = '$';
+ salt[length + 4] = '\0';
+
+ return salt;
+}
+
+static char *
+make_sha512_salt_para(const char *saltpara)
+{
+ static char salt[21];
+
+ if (saltpara && (strlen(saltpara) <= 16))
+ {
+ /*
+ * sprintf used because of portability requirements, the length
+ * is checked above, so it should not be too much of a concern
+ */
+ sprintf(salt, "$6$%s$", saltpara);
+ return salt;
+ }
+
+ printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
+ exit(1);
+
+ /* NOT REACHED */
+ return NULL;
+}
+
+static char *
+make_sha512_salt(int length)
+{
+ static char salt[21];
+
+ if (length > 16)
+ {
+ printf("SHA512 salt length too long\n");
+ exit(0);
+ }
+
+ salt[0] = '$';
+ salt[1] = '6';
+ salt[2] = '$';
+
+ generate_random_salt(&salt[3], length);
+
+ salt[length + 3] = '$';
+ salt[length + 4] = '\0';
+
+ return salt;
+}
+
+static char *
+make_md5_salt_para(const char *saltpara)
+{
+ static char salt[21];
+
+ if (saltpara && (strlen(saltpara) <= 16))
+ {
+ /*
+ * sprintf used because of portability requirements, the length
+ * is checked above, so it should not be too much of a concern
+ */
+ sprintf(salt, "$1$%s$", saltpara);
+ return salt;
+ }
+
+ printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
+ exit(1);
+
+ /* NOT REACHED */
+ return NULL;
+}
+
+static char *
+make_md5_salt(int length)
+{
+ static char salt[21];
+
+ if (length > 16)
+ {
+ printf("MD5 salt length too long\n");
+ exit(0);
+ }
+
+ salt[0] = '$';
+ salt[1] = '1';
+ salt[2] = '$';
+
+ generate_random_salt(&salt[3], length);
+
+ salt[length + 3] = '$';
+ salt[length + 4] = '\0';
+
+ return salt;
+}
+
+static char *
+make_bf_salt_para(int rounds, const char *saltpara)
+{
+ static char salt[31];
+ char tbuf[3];
+
+ if (saltpara && (strlen(saltpara) <= 22))
+ {
+ /*
+ * sprintf used because of portability requirements, the length
+ * is checked above, so it should not be too much of a concern
+ */
+ sprintf(tbuf, "%02d", rounds);
+ sprintf(salt, "$2a$%s$%s$", tbuf, saltpara);
+ return salt;
+ }
+
+ printf("Invalid Salt, please use up to 22 random alphanumeric characters\n");
+ exit(1);
+
+ /* NOT REACHED */
+ return NULL;
+}
+
+static char *
+make_bf_salt(int rounds, int length)
+{
+ static char salt[31];
+ char tbuf[3];
+
+ if (length > 22)
+ {
+ printf("BlowFish salt length too long\n");
+ exit(0);
+ }
+
+ sprintf(tbuf, "%02d", rounds);
+ sprintf(salt, "$2a$%s$", tbuf);
+
+ generate_random_salt(&salt[7], length);
+
+ salt[length + 7] = '$';
+ salt[length + 8] = '\0';
+
+ return salt;
+}
+
+static char *
+generate_poor_salt(char *salt, int length)
+{
+ int i;
+
+ srandom(time(NULL));
+
+ for (i = 0; i < length; i++)
+ salt[i] = saltChars[random() % 64];
+
+ return salt;
+}
+
+static char *
+generate_random_salt(char *salt, int length)
+{
+ char *buf;
+ int fd, i;
+
+ if ((fd = open("/dev/random", O_RDONLY)) < 0)
+ return generate_poor_salt(salt, length);
+
+ buf = calloc(1, length);
+
+ if (read(fd, buf, length) != length)
+ {
+ close(fd);
+ free(buf);
+
+ return generate_poor_salt(salt, length);
+ }
+
+ for (i = 0; i < length; i++)
+ salt[i] = saltChars[abs(buf[i]) % 64];
+
+ close(fd);
+ free(buf);
+
+ return salt;
+}
+
+static void
+full_usage(void)
+{
+ printf("mkpasswd [-5|-6|-m|-d|-b|-e] [-l saltlength] [-r rounds] [-s salt] [-p plaintext]\n");
+ printf(" [-R rawsalt]\n");
+ printf("-5 Generate a SHA-256 password\n");
+ printf("-6 Generate a SHA-512 password\n");
+ printf("-m Generate an MD5 password\n");
+ printf("-d Generate a DES password\n");
+ printf("-b Generate a BlowFish password\n");
+ printf("-e Generate an Extended DES password\n");
+ printf("-l Specify a length for a random MD5 or BlowFish salt\n");
+ printf("-r Specify a number of rounds for a BlowFish or Extended DES password\n");
+ printf(" BlowFish: default 4, no more than 6 recommended\n");
+ printf(" Extended DES: default 25\n");
+ printf("-s Specify a salt, 2 alphanumeric characters for DES, up to 16 for SHA/MD5,\n");
+ printf(" up to 22 for BlowFish, and 4 for Extended DES\n");
+ printf("-R Specify a raw salt passed directly to crypt()\n");
+ printf("-p Specify a plaintext password to use\n");
+ printf("Example: mkpasswd -m -s 3dr -p test\n");
+ exit(0);
+}
+
+static void
+brief_usage(void)
+{
+ printf("mkpasswd - password hash generator\n");
+ printf("Standard DES: mkpasswd [-d] [-s salt] [-p plaintext]\n");
+ printf("Extended DES: mkpasswd -e [-r rounds] [-s salt] [-p plaintext]\n");
+ printf(" SHA-256: mkpasswd -5 [-l saltlength] [-s salt] [-p plaintext]\n");
+ printf(" SHA-512: mkpasswd -6 [-l saltlength] [-s salt] [-p plaintext]\n");
+ printf(" MD5: mkpasswd -m [-l saltlength] [-s salt] [-p plaintext]\n");
+ printf(" BlowFish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
+ printf(" [-p plaintext]\n");
+ printf(" Raw: mkpasswd -R <rawsalt> [-p plaintext]\n");
+ printf("Use -h for full usage\n");
+ exit(0);
+}