ChangeLog | 2 +- Makefile.am | 14 ++- configure.ac | 19 +++- getline.h | 39 +++++++ getpass.c | 182 +++++++++++++++++++++++++++++++++ getpass.h | 7 ++ hashalot.1 | 42 -------- hashalot.8 | 42 ++++++++ hashalot.c | 323 +++++++++++++++++++++++++++++++--------------------------- sha512.c | 14 +-- sha512.h | 10 +- unlocked-io.h | 132 ++++++++++++++++++++++++ 12 files changed, 614 insertions(+), 212 deletions(-) diff --git a/ChangeLog b/ChangeLog index b3fd1f7..909db3c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,7 +23,7 @@ * forgot to erase the passphrase from memory when using a salt * manpage created - + 2004-02-08 Ben Slusky diff --git a/Makefile.am b/Makefile.am index 4fcc6fd..973e063 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,9 @@ sbin_PROGRAMS = hashalot -man_MANS = hashalot.1 +man_MANS = hashalot.8 -hashalot_SOURCES = hashalot.c rmd160.c rmd160.h sha512.c sha512.h +hashalot_SOURCES = hashalot.c getpass.c rmd160.c rmd160.h sha512.c sha512.h install-exec-hook: cd $(DESTDIR)$(sbindir) && \ @@ -12,9 +12,19 @@ install-exec-hook: $(LN_S) -f hashalot$(EXEEXT) sha384$(EXEEXT) && \ $(LN_S) -f hashalot$(EXEEXT) sha512$(EXEEXT) +install-data-hook: + cd $(DESTDIR)$(mandir)/man8 && \ + $(LN_S) -f hashalot.8 rmd160.8 && \ + $(LN_S) -f hashalot.8 sha256.8 && \ + $(LN_S) -f hashalot.8 sha384.8 && \ + $(LN_S) -f hashalot.8 sha512.8 + uninstall-hook: cd $(DESTDIR)$(sbindir) && \ rm -f rmd160 sha256 sha384 sha512 + cd $(DESTDIR)$(mandir)/man8 && \ + rm -f rmd160.8 sha256.8 sha384.8 sha512.8 TESTS = check.sh +EXTRA_DIST = check.sh diff --git a/configure.ac b/configure.ac index d14db24..31996c2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,12 +1,25 @@ AC_INIT(hashalot.c) -AM_INIT_AUTOMAKE(hashalot, 0.1.0) +AM_INIT_AUTOMAKE(hashalot, 0.3.0) +AC_CONFIG_HEADERS([config.h]) +AC_GNU_SOURCE AC_PROG_INSTALL AC_PROG_CC AC_PROG_LN_S AC_HEADER_STDC -AC_CHECK_HEADERS(libgen.h stdio.h stdlib.h string.h unistd.h assert.h sys/types.h sys/mman.h endian.h , , [ AC_MSG_ERROR(required header not found)]) -AC_CHECK_FUNCS(getopt snprintf , , [ AC_MSG_ERROR(required function not found)]) +AC_CHECK_HEADERS( + [errno.h error.h stdbool.h stddef.h stdio.h stdio_ext.h \ + stdlib.h string.h unistd.h sys/types.h sys/mman.h endian.h], , + [AC_MSG_ERROR(required header not found)]) +AC_CHECK_FUNCS( + [asprintf error getline getopt snprintf tcgetattr], , + [AC_MSG_ERROR(required function not found)]) + +AC_CHECK_DECLS( + [clearerr_unlocked, feof_unlocked, ferror_unlocked, + fflush_unlocked, fgets_unlocked, fputc_unlocked, fputs_unlocked, + fread_unlocked, fwrite_unlocked, getc_unlocked, + getchar_unlocked, putc_unlocked, putchar_unlocked]) AC_OUTPUT(Makefile) diff --git a/getline.h b/getline.h new file mode 100644 index 0000000..ee9fc05 --- /dev/null +++ b/getline.h @@ -0,0 +1,39 @@ +/* Replacement for GNU C library function getline + + Copyright (C) 1995, 1997, 1999, 2000, 2001, 2002, 2003 Free + Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef GETLINE_H_ +# define GETLINE_H_ 1 + +# include +# include + +/* Get ssize_t. */ +# include + +/* glibc2 has these functions declared in . Avoid redeclarations. */ +# if __GLIBC__ < 2 + +extern ssize_t getline (char **_lineptr, size_t *_linesize, FILE *_stream); + +extern ssize_t getdelim (char **_lineptr, size_t *_linesize, int _delimiter, + FILE *_stream); + +# endif + +#endif /* not GETLINE_H_ */ diff --git a/getpass.c b/getpass.c new file mode 100644 index 0000000..c46966f --- /dev/null +++ b/getpass.c @@ -0,0 +1,182 @@ +/* Copyright (C) 1992-2001, 2003 Free Software Foundation, Inc. + This file was part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include +#endif + +#if _LIBC +# define HAVE_STDIO_EXT_H 1 +#endif + +#include + +#include +#include +#include +#if HAVE_STDIO_EXT_H +# include +#else +# define __fsetlocking(stream, type) /* empty */ +#endif +#if !_LIBC +# include "getline.h" +#endif + +#include +#include + +#if _LIBC +# include +#endif + +#if _LIBC +# define NOTCANCEL_MODE "c" +#else +# define NOTCANCEL_MODE +#endif + +#if _LIBC +# define flockfile(s) _IO_flockfile (s) +# define funlockfile(s) _IO_funlockfile (s) +#else +# include "unlocked-io.h" +#endif + +#if _LIBC +# include +#else +# define __libc_cleanup_push(function, arg) /* empty */ +# define __libc_cleanup_pop(execute) /* empty */ +#endif + +#if !_LIBC +# define __getline getline +# define __tcgetattr tcgetattr +#endif + +/* It is desirable to use this bit on systems that have it. + The only bit of terminal state we want to twiddle is echoing, which is + done in software; there is no need to change the state of the terminal + hardware. */ + +#ifndef TCSASOFT +# define TCSASOFT 0 +#endif + +static void +call_fclose (void *arg) +{ + if (arg != NULL) + fclose (arg); +} + +char * +xgetpass (const char *prompt) +{ + FILE *tty; + FILE *in, *out; + struct termios s, t; + bool tty_changed; + char *buf = NULL; + size_t bufsize = 0; + ssize_t nread; + + /* Try to write to and read from the terminal if we can. + If we can't open the terminal, use stderr and stdin. */ + + tty = fopen ("/dev/tty", "w+" NOTCANCEL_MODE); + if (tty == NULL) + { + in = stdin; + out = stderr; + } + else + { + /* We do the locking ourselves. */ + __fsetlocking (tty, FSETLOCKING_BYCALLER); + + out = in = tty; + } + + /* Make sure the stream we opened is closed even if the thread is + canceled. */ + __libc_cleanup_push (call_fclose, tty); + + flockfile (out); + + /* Turn echoing off if it is on now. */ + + if (__tcgetattr (fileno (in), &t) == 0) + { + /* Save the old one. */ + s = t; + /* Tricky, tricky. */ + t.c_lflag &= ~(ECHO|ISIG); + tty_changed = (tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &t) == 0); + } + else + tty_changed = false; + + /* Write the prompt. */ +#ifdef USE_IN_LIBIO + if (_IO_fwide (out, 0) > 0) + __fwprintf (out, L"%s", prompt); + else +#endif + fputs_unlocked (prompt, out); + fflush_unlocked (out); + + /* Read the password. */ + errno = 0; + nread = __getline (&buf, &bufsize, in); + + if (buf != NULL) + { + if (nread < 0) + { + free (buf); + buf = NULL; + } + else if ((nread > 0) && (buf[nread - 1] == '\n')) + { + /* Remove the newline. */ + buf[nread - 1] = '\0'; + } + } + + if (tty_changed) + { + /* Write the newline that was not echoed. */ +#ifdef USE_IN_LIBIO + if (_IO_fwide (out, 0) > 0) + putwc_unlocked (L'\n', out); + else +#endif + putc_unlocked ('\n', out); + /* Restore the original setting. */ + (void) tcsetattr (fileno (in), TCSAFLUSH|TCSASOFT, &s); + } + + funlockfile (out); + + __libc_cleanup_pop (0); + + call_fclose (tty); + + return buf; +} diff --git a/getpass.h b/getpass.h new file mode 100644 index 0000000..131947c --- /dev/null +++ b/getpass.h @@ -0,0 +1,7 @@ +#ifndef GETPASS_H_ +#define GETPASS_H_ + +char * +xgetpass (const char *prompt); + +#endif /* GETPASS_H_ */ diff --git a/hashalot.1 b/hashalot.1 deleted file mode 100644 index 20ace86..0000000 --- a/hashalot.1 +++ /dev/null @@ -1,42 +0,0 @@ -.TH HASHALOT 1 "09 Feb 2004" -.SH NAME -hashalot \- read a passphrase and print a hash -.SH SYNOPSIS -.B hashalot [ \-s SALT ] [ \-x ] [ \-n #BYTES ] HASHTYPE -.br -.B HASHTYPE [ \-s SALT ] [ \-x ] [ \-n #BYTES ] -.SH DESCRIPTION -.PP -\fIhashalot\fP is a small tool that reads a passphrase from standard -input, hashes it using the given hash type, and prints the result to -standard output. -.PP -Supported values for \fIHASHTYPE\fP: -.br -.RS 8 -ripemd160 rmd160 rmd160compat sha256 sha384 sha512 -.RE -.PP -.SH OPTIONS -.l -The option -.B \-s \fISALT\fP -specifies an initialization vector to the hashing algorithm. You need -this if you want to prevent identical passwords to map to identical -hashes, which is a security risk. -.PP -If the -.B \-x -option is given then the hash will be printed as a string of hexadecimal -digits. -.PP -The -.B \-n -option can be used to limit (or increase) the number of bytes output. The -default is as appropriate for the specified hash algorithm: 20 bytes for -RIPEMD160, 32 bytes for SHA256, etc. The default for the "rmd160compat" -hash is 16 bytes, for compatibility with the old kerneli.org utilities. -.SH AUTHOR -Ben Slusky -.PP -This manual page was written by Matthias Urlichs . diff --git a/hashalot.8 b/hashalot.8 new file mode 100644 index 0000000..20ace86 --- /dev/null +++ b/hashalot.8 @@ -0,0 +1,42 @@ +.TH HASHALOT 1 "09 Feb 2004" +.SH NAME +hashalot \- read a passphrase and print a hash +.SH SYNOPSIS +.B hashalot [ \-s SALT ] [ \-x ] [ \-n #BYTES ] HASHTYPE +.br +.B HASHTYPE [ \-s SALT ] [ \-x ] [ \-n #BYTES ] +.SH DESCRIPTION +.PP +\fIhashalot\fP is a small tool that reads a passphrase from standard +input, hashes it using the given hash type, and prints the result to +standard output. +.PP +Supported values for \fIHASHTYPE\fP: +.br +.RS 8 +ripemd160 rmd160 rmd160compat sha256 sha384 sha512 +.RE +.PP +.SH OPTIONS +.l +The option +.B \-s \fISALT\fP +specifies an initialization vector to the hashing algorithm. You need +this if you want to prevent identical passwords to map to identical +hashes, which is a security risk. +.PP +If the +.B \-x +option is given then the hash will be printed as a string of hexadecimal +digits. +.PP +The +.B \-n +option can be used to limit (or increase) the number of bytes output. The +default is as appropriate for the specified hash algorithm: 20 bytes for +RIPEMD160, 32 bytes for SHA256, etc. The default for the "rmd160compat" +hash is 16 bytes, for compatibility with the old kerneli.org utilities. +.SH AUTHOR +Ben Slusky +.PP +This manual page was written by Matthias Urlichs . diff --git a/hashalot.c b/hashalot.c index 8823dea..c31ec4a 100644 --- a/hashalot.c +++ b/hashalot.c @@ -6,77 +6,89 @@ ** an encryption key. ** ** USAGE: -** hashalot [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] _hashtype_ +** hashalot [ -q ] [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] _hashtype_ ** OR -** _hashtype_ [ -x ] [ -s _salt_ ] [ -n _#bytes_ ] +** _hashtype_ [ -q ] [ -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 +#if HAVE_CONFIG_H +# include +#endif + #include #include #include #include -#include +#include +#include #include #include #include "rmd160.h" #include "sha512.h" +#include "getpass.h" #define PASSWDBUFFLEN 130 -typedef int (*phash_func_t)(char dest[], size_t dest_len, const char src[], size_t src_len); +const char *progname; + +typedef int (*phash_func_t) (char *dest, size_t dest_len, + const char *src, size_t src_len); static int -phash_rmd160(char dest[], size_t dest_len, const char src[], size_t src_len) +phash_rmd160(char *dest, size_t dest_len, const char *src, size_t src_len) { - char tmp[PASSWDBUFFLEN] = { 'A', 0, }; - char key[RMD160_HASH_SIZE * 2] = { 0, }; + char tmp[PASSWDBUFFLEN] = { 'A', 0, }; + char key[RMD160_HASH_SIZE * 2] = { 0, }; + + strncat(tmp, src, sizeof(tmp) - 1); - strncpy(tmp + 1, src, PASSWDBUFFLEN - 1); - tmp[PASSWDBUFFLEN - 1] = '\0'; - rmd160_hash_buffer(key, src, src_len); - rmd160_hash_buffer(key + RMD160_HASH_SIZE, tmp, src_len + 1 /* dangerous! */); + rmd160_hash_buffer(key + RMD160_HASH_SIZE, tmp, + src_len + 1 /* dangerous! */ ); memcpy(dest, key, dest_len); - memset (tmp, 0, PASSWDBUFFLEN); /* paranoia */ - memset (key, 0, RMD160_HASH_SIZE * 2); /* paranoia */ + memset(tmp, 0, sizeof tmp); /* paranoia */ + memset(key, 0, sizeof key); /* paranoia */ return dest_len; } static int -phash_sha256(char dest[], size_t dest_len, const char src[], size_t src_len) +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); + sha256_hash_buffer((const unsigned char *) src, src_len, + (unsigned char *) dest, dest_len); return dest_len; } static int -phash_sha384(char dest[], size_t dest_len, const char src[], size_t src_len) +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); + sha384_hash_buffer((const unsigned char *) src, src_len, + (unsigned char *) dest, dest_len); return dest_len; } static int -phash_sha512(char dest[], size_t dest_len, const char src[], size_t src_len) +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); + sha512_hash_buffer((const unsigned char *) src, src_len, + (unsigned char *) dest, dest_len); return dest_len; } -struct func_table_t { +struct func_table_t +{ const char *name; phash_func_t func; size_t def_length; @@ -90,197 +102,204 @@ struct func_table_t { { 0, 0, 0 } }; -static int -show_usage(const char argv0[]) +static int __attribute__ ((__noreturn__)) +show_usage(void) { 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: "); + fprintf(stderr, + "usage:\n" + " hashalot [ -q ] [ -x ] [ -s SALT ] [ -n _#bytes_ ] HASHTYPE\n" + " or\n" + " HASHTYPE [ -q ] [ -x ] [ -s SALT ] [ -n _#bytes_ ]\n" + "\n" "supported values for HASHTYPE:"); for (; p->name; ++p) - fprintf (stderr, "%s ", p->name); + fprintf(stderr, " %s", p->name); + + fprintf(stderr, "\n"); - fprintf (stderr, "\n"); - - return 1; + exit(EXIT_FAILURE); } -static phash_func_t -phash_lookup(const char phash_name[], size_t *length) +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; + 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) +zeroize(char *str) { - 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; + char *p = str; - p = malloc(size); - if (p == NULL) { - perror("malloc"); - exit(1); - } - - return p; + while (*p) + *p++ = '\0'; + return str; } /* function to append a "salt" to the passphrase, to better resist * dictionary attacks */ static char * -salt_passphrase(char *pass, char *salt) { - char *buf = xmalloc(strlen(pass) + strlen(salt) + 1); - sprintf(buf, "%s%s", pass, salt); +salt_passphrase(char *pass, const char *salt) +{ + char *buf; + int rc; - memset (pass, 0, strlen (pass)); /* paranoia */ - free(pass); + rc = asprintf(&buf, "%s%s", pass, salt); + zeroize(pass); + if (rc < 0) + error(EXIT_FAILURE, errno, "asprintf"); + free(pass); return buf; } +static void * +xmalloc(size_t size) +{ + void *r = malloc(size); + + if (!r) + error(EXIT_FAILURE, errno, "malloc"); + return r; +} + static void -hexify(char *hash, size_t hashlen) { - int i; - char *h = xmalloc(hashlen); - memcpy(h, hash, hashlen); +hexify(char *hash, size_t hashlen) +{ + int i; + char *h = xmalloc(hashlen); - for (i=0; i < hashlen; i++) - snprintf((hash + 2*i), 3, "%.2x", (unsigned char) h[i]); + 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 */ + memset(h, 0, hashlen); /* paranoia */ free(h); } +static int +write_loop(int fd, const char *buffer, size_t count) +{ + ssize_t offset = 0; + + while (count > 0) + { + ssize_t block = write(fd, &buffer[offset], count); + + if (block < 0) + { + if (errno == EINTR) + continue; + return block; + } + if (!block) + break; + offset += block; + count -= block; + } + return offset; +} + int -main(int argc, char *argv[]) +main(int argc, char *argv[]) { - char *pass, *passhash, *salt = NULL, *p; - size_t hashlen = 0; + char *pass, *passhash, *salt = NULL, *p; + size_t hashlen = 0; phash_func_t func; - int hex_output = 0, c; - - while ((c = getopt(argc, argv, "n:s:x")) != -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 'x': - hex_output++; - break; - default: - show_usage(argv[0]); - exit(EXIT_FAILURE); - } + int quiet = 0, hex_output = 0, c; + int rc = EXIT_SUCCESS; + + progname = (argc > 0) ? basename(argv[0]) : "hashalot"; + + while ((c = getopt(argc, argv, "n:qs:x")) != -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", + progname); + show_usage(); + exit(EXIT_FAILURE); + } + break; + case 'q': + quiet = 1; + break; + case 's': + salt = optarg; + break; + case 'x': + hex_output = 1; + break; + default: + return EXIT_FAILURE; + } } - if (!(func = phash_lookup(basename(argv[0]), (hashlen ? NULL : &hashlen)))) + if (!(func = phash_lookup(progname, (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); + if (optind + 1 != argc) + show_usage(); + func = phash_lookup(argv[optind], + (hashlen ? NULL : &hashlen)); + if (!func) + { + /* lookup failed again */ + fprintf(stderr, + "%s: missing or unknown hash type requested\n", + progname); + show_usage(); + } + } /* 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); + 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) { - perror("mlockall"); - fputs("Warning: couldn't lock memory, are you root?\n", stderr); - } + if (mlockall(MCL_CURRENT | MCL_FUTURE) && !quiet) + error(EXIT_SUCCESS, errno, "failed to lock memory"); /* here we acquire the precious passphrase... */ - pass = xgetpass("Enter passphrase: "); + if (!(pass = xgetpass("Enter passphrase: "))) + error(EXIT_FAILURE, errno, "getpass failed"); if (salt) pass = salt_passphrase(pass, salt); hashlen = func(passhash, hashlen, pass, strlen(pass)); - memset (pass, 0, strlen (pass)); /* paranoia */ - free(pass); + free(zeroize(pass)); - if (hex_output) { + if (hex_output) + { hexify(passhash, hashlen); hashlen = hashlen * 2 + 1; } - if (write(STDOUT_FILENO, passhash, hashlen) != hashlen) - perror("write"); + if (write_loop(STDOUT_FILENO, passhash, hashlen) != hashlen) + { + error(EXIT_SUCCESS, errno, "write"); + rc = EXIT_FAILURE; + } - memset (passhash, 0, hashlen); /* paranoia again */ + memset(passhash, 0, hashlen); /* paranoia again */ free(passhash); - exit(EXIT_SUCCESS); + return rc; } - diff --git a/sha512.c b/sha512.c index a795228..e8f72bd 100644 --- a/sha512.c +++ b/sha512.c @@ -104,7 +104,7 @@ void sha256_init(sha256_context *ctx) #define lSig0(x) ((S(7,(x))) ^ (S(18,(x))) ^ (R(3,(x)))) #define lSig1(x) ((S(17,(x))) ^ (S(19,(x))) ^ (R(10,(x)))) -static void sha256_transform(sha256_context *ctx, unsigned char *datap) +static void sha256_transform(sha256_context *ctx, const unsigned char *datap) { register int j; u_int32_t a, b, c, d, e, f, g, h; @@ -157,7 +157,7 @@ static void sha256_transform(sha256_context *ctx, unsigned char *datap) ctx->sha_blocks++; } -void sha256_write(sha256_context *ctx, unsigned char *datap, int length) +void sha256_write(sha256_context *ctx, const unsigned char *datap, int length) { while(length > 0) { if(!ctx->sha_bufCnt) { @@ -221,7 +221,7 @@ void sha256_final(sha256_context *ctx) memset(&ctx->sha_out[32], 0, sizeof(sha256_context) - 32); } -void sha256_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole) +void sha256_hash_buffer(const unsigned char *ib, int ile, unsigned char *ob, int ole) { sha256_context ctx; @@ -259,7 +259,7 @@ void sha512_init(sha512_context *ctx) #define lSig0(x) ((S(1,(x))) ^ (S(8,(x))) ^ (R(7,(x)))) #define lSig1(x) ((S(19,(x))) ^ (S(61,(x))) ^ (R(6,(x)))) -static void sha512_transform(sha512_context *ctx, unsigned char *datap) +static void sha512_transform(sha512_context *ctx, const unsigned char *datap) { register int j; u_int64_t a, b, c, d, e, f, g, h; @@ -315,7 +315,7 @@ static void sha512_transform(sha512_context *ctx, unsigned char *datap) if(!ctx->sha_blocks) ctx->sha_blocksMSB++; } -void sha512_write(sha512_context *ctx, unsigned char *datap, int length) +void sha512_write(sha512_context *ctx, const unsigned char *datap, int length) { while(length > 0) { if(!ctx->sha_bufCnt) { @@ -392,7 +392,7 @@ void sha512_final(sha512_context *ctx) memset(&ctx->sha_out[64], 0, sizeof(sha512_context) - 64); } -void sha512_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole) +void sha512_hash_buffer(const unsigned char *ib, int ile, unsigned char *ob, int ole) { sha512_context ctx; @@ -416,7 +416,7 @@ void sha384_init(sha512_context *ctx) ctx->sha_bufCnt = 0; } -void sha384_hash_buffer(unsigned char *ib, int ile, unsigned char *ob, int ole) +void sha384_hash_buffer(const unsigned char *ib, int ile, unsigned char *ob, int ole) { sha512_context ctx; diff --git a/sha512.h b/sha512.h index 817dc26..5f5e4fc 100644 --- a/sha512.h +++ b/sha512.h @@ -28,18 +28,18 @@ typedef struct { /* 256 bit hash, provides 128 bits of security against collision attacks */ extern void sha256_init(sha256_context *); -extern void sha256_write(sha256_context *, unsigned char *, int); +extern void sha256_write(sha256_context *, const unsigned char *, int); extern void sha256_final(sha256_context *); -extern void sha256_hash_buffer(unsigned char *, int, unsigned char *, int); +extern void sha256_hash_buffer(const unsigned char *, int, unsigned char *, int); /* 512 bit hash, provides 256 bits of security against collision attacks */ extern void sha512_init(sha512_context *); -extern void sha512_write(sha512_context *, unsigned char *, int); +extern void sha512_write(sha512_context *, const unsigned char *, int); extern void sha512_final(sha512_context *); -extern void sha512_hash_buffer(unsigned char *, int, unsigned char *, int); +extern void sha512_hash_buffer(const unsigned char *, int, unsigned char *, int); /* 384 bit hash, provides 192 bits of security against collision attacks */ extern void sha384_init(sha512_context *); /* no sha384_write(), use sha512_write() */ /* no sha384_final(), use sha512_final(), result in ctx->sha_out[0...47] */ -extern void sha384_hash_buffer(unsigned char *, int, unsigned char *, int); +extern void sha384_hash_buffer(const unsigned char *, int, unsigned char *, int); diff --git a/unlocked-io.h b/unlocked-io.h new file mode 100644 index 0000000..36a7a48 --- /dev/null +++ b/unlocked-io.h @@ -0,0 +1,132 @@ +/* Prefer faster, non-thread-safe stdio functions if available. + + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering. */ + +#ifndef UNLOCKED_IO_H +# define UNLOCKED_IO_H 1 + +# ifndef USE_UNLOCKED_IO +# define USE_UNLOCKED_IO 1 +# endif + +# if USE_UNLOCKED_IO + +/* These are wrappers for functions/macros from the GNU C library, and + from other C libraries supporting POSIX's optional thread-safe functions. + + The standard I/O functions are thread-safe. These *_unlocked ones are + more efficient but not thread-safe. That they're not thread-safe is + fine since all of the applications in this package are single threaded. + + Also, some code that is shared with the GNU C library may invoke + the *_unlocked functions directly. On hosts that lack those + functions, invoke the non-thread-safe versions instead. */ + +# include + +# if HAVE_DECL_CLEARERR_UNLOCKED +# undef clearerr +# define clearerr(x) clearerr_unlocked (x) +# else +# define clearerr_unlocked(x) clearerr (x) +# endif +# if HAVE_DECL_FEOF_UNLOCKED +# undef feof +# define feof(x) feof_unlocked (x) +# else +# define feof_unlocked(x) feof (x) +# endif +# if HAVE_DECL_FERROR_UNLOCKED +# undef ferror +# define ferror(x) ferror_unlocked (x) +# else +# define ferror_unlocked(x) ferror (x) +# endif +# if HAVE_DECL_FFLUSH_UNLOCKED +# undef fflush +# define fflush(x) fflush_unlocked (x) +# else +# define fflush_unlocked(x) fflush (x) +# endif +# if HAVE_DECL_FGETS_UNLOCKED +# undef fgets +# define fgets(x,y,z) fgets_unlocked (x,y,z) +# else +# define fgets_unlocked(x,y,z) fgets (x,y,z) +# endif +# if HAVE_DECL_FPUTC_UNLOCKED +# undef fputc +# define fputc(x,y) fputc_unlocked (x,y) +# else +# define fputc_unlocked(x,y) fputc (x,y) +# endif +# if HAVE_DECL_FPUTS_UNLOCKED +# undef fputs +# define fputs(x,y) fputs_unlocked (x,y) +# else +# define fputs_unlocked(x,y) fputs (x,y) +# endif +# if HAVE_DECL_FREAD_UNLOCKED +# undef fread +# define fread(w,x,y,z) fread_unlocked (w,x,y,z) +# else +# define fread_unlocked(w,x,y,z) fread (w,x,y,z) +# endif +# if HAVE_DECL_FWRITE_UNLOCKED +# undef fwrite +# define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z) +# else +# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) +# endif +# if HAVE_DECL_GETC_UNLOCKED +# undef getc +# define getc(x) getc_unlocked (x) +# else +# define getc_unlocked(x) getc (x) +# endif +# if HAVE_DECL_GETCHAR_UNLOCKED +# undef getchar +# define getchar() getchar_unlocked () +# else +# define getchar_unlocked() getchar () +# endif +# if HAVE_DECL_PUTC_UNLOCKED +# undef putc +# define putc(x,y) putc_unlocked (x,y) +# else +# define putc_unlocked(x,y) putc (x,y) +# endif +# if HAVE_DECL_PUTCHAR_UNLOCKED +# undef putchar +# define putchar(x) putchar_unlocked (x) +# else +# define putchar_unlocked(x) putchar (x) +# endif + +# undef flockfile +# define flockfile(x) ((void) 0) + +# undef ftrylockfile +# define ftrylockfile(x) 0 + +# undef funlockfile +# define funlockfile(x) ((void) 0) + +# endif /* USE_UNLOCKED_IO */ +#endif /* UNLOCKED_IO_H */