/* ** Hash-A-Lot by Ben Slusky ** ** This program will read a passphrase from standard input and print a binary ** (not printable) hash to standard output. The output is suitable for use as ** an encryption key. ** ** USAGE: ** hashalot [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] _hashtype_ ** OR ** _hashtype_ [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] ** ** Most of the code was cribbed from the kerneli.org patch to util-linux, ** by Marc Mutz . Most of what wasn't, was cribbed from GnuPG, ** v.1.0.3 (http://www.gnupg.org/). */ #include #include #include #include #include #include #include #include #include "rmd160.h" #include "sha512.h" typedef int (*phash_func_t)(char dest[], size_t dest_len, const char src[], size_t src_len); static void * xmalloc (size_t size); static int phash_rmd160(char dest[], size_t dest_len, const char src[], size_t src_len) { char key[RMD160_HASH_SIZE * 2] = { 0, }; char *tmp = xmalloc(src_len + 2); tmp[0] = 'A'; tmp[1] = '\0'; strncpy(tmp + 1, src, src_len); tmp[src_len + 1] = '\0'; rmd160_hash_buffer(key, src, src_len); rmd160_hash_buffer(key + RMD160_HASH_SIZE, tmp, src_len + 1); memcpy(dest, key, dest_len); memset (tmp, 0, src_len + 2); /* paranoia */ memset (key, 0, RMD160_HASH_SIZE * 2); /* paranoia */ return dest_len; } static int phash_sha256(char dest[], size_t dest_len, const char src[], size_t src_len) { memset(dest, 0, dest_len); sha256_hash_buffer((char *) src, src_len, dest, dest_len); return dest_len; } static int phash_sha384(char dest[], size_t dest_len, const char src[], size_t src_len) { memset(dest, 0, dest_len); sha384_hash_buffer((char *) src, src_len, dest, dest_len); return dest_len; } static int phash_sha512(char dest[], size_t dest_len, const char src[], size_t src_len) { memset(dest, 0, dest_len); sha512_hash_buffer((char *) src, src_len, dest, dest_len); return dest_len; } struct func_table_t { const char *name; phash_func_t func; size_t def_length; } static func_table[] = { { "ripemd160", phash_rmd160, 20 }, { "rmd160", phash_rmd160, 20 }, { "rmd160compat", phash_rmd160, 16 }, { "sha256", phash_sha256, 32 }, { "sha384", phash_sha384, 48 }, { "sha512", phash_sha512, 64 }, { 0, 0, 0 } }; static int show_usage(const char argv0[]) { struct func_table_t *p = func_table; fprintf (stderr, "usage:\n" " hashalot [ -x ] [ -s SALT ] [ -n _#bytes_ ] HASHTYPE\n" " or\n" " HASHTYPE [ -x ] [ -s SALT ] [ -n _#bytes_ ]\n" "\n" "supported values for HASHTYPE: "); for (; p->name; ++p) fprintf (stderr, "%s ", p->name); fprintf (stderr, "\n"); return 1; } static phash_func_t phash_lookup(const char phash_name[], size_t *length) { struct func_table_t *p = func_table; if (!phash_name) return 0; for (; p->name && strcmp(phash_name, p->name); ++p); if (length) *length = p->def_length; return p->func; } /* A function to read the passphrase either from the terminal or from * an open file descriptor */ static char * xgetpass(const char *prompt) { if (isatty(STDIN_FILENO)) /* terminal */ return getpass(prompt); /* FIXME getpass(3) obsolete */ else { /* file descriptor */ char *pass = NULL; int buflen, i; buflen=0; for (i=0; ; i++) { if (i >= buflen - 1) { /* we're running out of space in the buffer. * Make it bigger: */ char *tmppass = pass; buflen += 128; pass = (char *) realloc(tmppass, buflen); if (pass == NULL) { /* realloc failed. Stop reading _now_. */ fprintf(stderr, "not enough memory while reading passphrase\n"); pass = tmppass; /* the old buffer hasn't changed */ break; } } if (read(STDIN_FILENO, pass+i, 1) != 1 || pass[i] == '\n') break; } if (pass == NULL) return ""; else { pass[i] = 0; return pass; } } } static void * xmalloc (size_t size) { void *p; if (size == 0) return NULL; p = malloc(size); if (p == NULL) { perror("malloc"); exit(1); } return p; } /* function to append a "salt" to the passphrase, to better resist * dictionary attacks */ static char * salt_passphrase(char *pass, const char *salt) { char *buf = xmalloc(strlen(pass) + strlen(salt) + 1); sprintf(buf, "%s%s", pass, salt); memset (pass, 0, strlen (pass)); /* paranoia */ free(pass); return buf; } static void hexify(char *hash, size_t hashlen) { int i; char *h = xmalloc(hashlen); memcpy(h, hash, hashlen); for (i=0; i < hashlen; i++) snprintf((hash + 2*i), 3, "%.2x", (unsigned char) h[i]); strcat(hash, "\n"); memset(h, 0, hashlen); /* paranoia */ free(h); } int main(int argc, char *argv[]) { char *pass, *passhash, *salt = NULL, *p; size_t hashlen = 0; phash_func_t func; int hex_output = 0, c; int quiet = 0; while ((c = getopt(argc, argv, "n:s:qx")) != -1) { switch (c) { case 'n': hashlen = strtoul(optarg, &p, 0); if (*p != '\0' || *optarg == '\0') { fprintf (stderr, "%s: argument to -n option must be numeric\n", argv[0]); show_usage(argv[0]); exit(EXIT_FAILURE); } break; case 's': salt = optarg; break; case 'q': quiet++; break; case 'x': hex_output++; break; default: show_usage(argv[0]); exit(EXIT_FAILURE); } } if (!(func = phash_lookup(basename(argv[0]), (hashlen ? NULL : &hashlen)))) /* lookup failed, so try next argv */ if (!(func = phash_lookup(argv[optind], (hashlen ? NULL : &hashlen)))) { /* lookup failed again */ fprintf (stderr, "%s: missing or unknown hash type requested\n", argv[0]); show_usage(argv[0]); exit(EXIT_FAILURE); } assert (func != 0); /* allocate memory for the password hash: * enough for 2 hex digits per byte of the requested hash length, * plus a newline, plus a null */ passhash = xmalloc(2*hashlen + 2); /* try to lock memory so it doesn't get swapped out for sure */ if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1 && !quiet) { perror("mlockall"); fputs("Warning: couldn't lock memory, are you root?\n", stderr); } /* here we acquire the precious passphrase... */ pass = xgetpass("Enter passphrase: "); if (salt) pass = salt_passphrase(pass, salt); hashlen = func(passhash, hashlen, pass, strlen(pass)); memset (pass, 0, strlen (pass)); /* paranoia */ free(pass); if (hex_output) { hexify(passhash, hashlen); hashlen = hashlen * 2 + 1; } if (write(STDOUT_FILENO, passhash, hashlen) != hashlen) perror("write"); memset (passhash, 0, hashlen); /* paranoia again */ free(passhash); exit(EXIT_SUCCESS); }