Logo Search packages:      
Sourcecode: hashalot version File versions  Download package

hashalot.c

/*
** Hash-A-Lot by Ben Slusky <sluskyb@paranoiacs.org>
** 
** 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 <Marc@Mutz.com>. Most of what wasn't, was cribbed from GnuPG,
** v.1.0.3 (http://www.gnupg.org/).
*/

#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

#include <sys/types.h>
#include <sys/mman.h>

#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);
}


Generated by  Doxygen 1.6.0   Back to index