X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/5af0f9cb18436918d1660e8dd217224a8dbe7aef..2a7c52031aa0096b4f20ec1dd72e5f6e08a19aa9:/hashsum.c diff --git a/hashsum.c b/hashsum.c index 0e537ee..9721410 100644 --- a/hashsum.c +++ b/hashsum.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: hashsum.c,v 1.2 2000/07/15 21:14:05 mdw Exp $ + * $Id$ * * Hash files using some secure hash function * * (c) 2000 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of Catacomb. * @@ -15,34 +15,23 @@ * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * Catacomb 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 Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with Catacomb; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: hashsum.c,v $ - * Revision 1.2 2000/07/15 21:14:05 mdw - * Missed `-e' out of the usage string. - * - * Revision 1.1 2000/07/15 20:52:34 mdw - * Useful replacement for `md5sum' with support for many different hash - * functions and for reading filename lists from `find'. - * - */ - /*----- Header files ------------------------------------------------------*/ #include "config.h" +#include #include #include #include @@ -57,35 +46,149 @@ #include #include -#include "ghash.h" +#include +#include +#include -#include "md4.h" -#include "md5.h" -#include "rmd128.h" -#include "rmd160.h" -#include "rmd256.h" -#include "rmd320.h" -#include "sha.h" -#include "tiger.h" +#include "ghash.h" +#include "cc.h" /*----- Static variables --------------------------------------------------*/ -static const gchash *hashtab[] = { - &md5, &md4, &sha, &rmd128, &rmd160, &rmd256, &rmd320, &tiger, - 0 -}; +#define f_binary 1u +#define f_bogus 2u +#define f_verbose 4u +#define f_check 8u +#define f_files 16u +#define f_raw 32u +#define f_oddhash 64u +#define f_escape 128u +#define f_oddenc 256u + +/*----- Encoding and decoding ---------------------------------------------*/ + +/* --- Hex encoding --- */ + +static void puthex(const octet *buf, size_t sz, FILE *fp) +{ + while (sz) { + fprintf(fp, "%02x", *buf++); + sz--; + } +} + +static size_t gethex(const char *p, octet *q, size_t sz, char **pp) +{ + size_t i = 0; + while (sz > 0 && + isxdigit((unsigned char)p[0]) && + isxdigit((unsigned char)p[1])) { + char buf[3]; + buf[0] = p[0]; + buf[1] = p[1]; + buf[2] = 0; + *q++ = strtoul(buf, 0, 16); + sz--; + p += 2; + i++; + } + if (pp) + *pp = (char *)p; + return (i); +} + +/* --- Base64 encoding --- */ + +static void putb64(const octet *buf, size_t sz, FILE *fp) +{ + base64_ctx b; + dstr d = DSTR_INIT; + + base64_init(&b); + b.indent = ""; + b.maxline = 0; + base64_encode(&b, buf, sz, &d); + base64_encode(&b, 0, 0, &d); + dstr_write(&d, fp); + dstr_destroy(&d); +} + +static size_t getb64(const char *p, octet *q, size_t sz, char **pp) +{ + base64_ctx b; + dstr d = DSTR_INIT; + size_t n = strlen(p); + + base64_init(&b); + base64_decode(&b, p, n, &d); + if (pp) *pp = (/*unconst*/ char *)p + n; + base64_decode(&b, 0, 0, &d); + assert(d.len <= sz); + memcpy(q, d.buf, sz); + n = d.len; + dstr_destroy(&d); + return (n); +} + +/* --- Base32 encoding --- */ + +static void putb32(const octet *buf, size_t sz, FILE *fp) +{ + base32_ctx b; + dstr d = DSTR_INIT; + + base32_init(&b); + b.indent = ""; + b.maxline = 0; + base32_encode(&b, buf, sz, &d); + base32_encode(&b, 0, 0, &d); + dstr_write(&d, fp); + dstr_destroy(&d); +} + +static size_t getb32(const char *p, octet *q, size_t sz, char **pp) +{ + base32_ctx b; + dstr d = DSTR_INIT; + size_t n = strlen(p); + + base32_init(&b); + base32_decode(&b, p, n, &d); + if (pp) *pp = (/*unconst*/ char *)p + n; + base32_decode(&b, 0, 0, &d); + assert(d.len <= sz); + memcpy(q, d.buf, sz); + n = d.len; + dstr_destroy(&d); + return (n); +} + +/* --- Table --- */ -enum { - f_binary = 1, - f_bogus = 2, - f_verbose = 4, - f_check = 8, - f_files = 16, - f_raw = 32, - f_oddhash = 64, - f_escape = 128 +typedef struct encodeops { + const char *name; + void (*put)(const octet *, size_t, FILE *); + size_t (*get)(const char *, octet *, size_t, char **); +} encodeops; + +static const encodeops encodingtab[] = { + { "hex", puthex, gethex }, + { "base64", putb64, getb64 }, + { "base32", putb32, getb32 }, + { 0, 0, 0 } }; +static const encodeops *getencoding(const char *ename) +{ + const encodeops *e; + + for (e = encodingtab; e->name; e++) { + if (strcmp(ename, e->name) == 0) + return (e); + } + return (0); +} + /*----- Support functions -------------------------------------------------*/ /* --- @fhash@ --- * @@ -108,73 +211,22 @@ static int fhash(const char *file, unsigned f, const gchash *gch, void *buf) ghash *h; int e; - if (!file) + if (!file || strcmp(file, "-") == 0) fp = stdin; else if ((fp = fopen(file, f & f_binary ? "rb" : "r")) == 0) return (-1); - h = gch->init(); + h = GH_INIT(gch); while ((sz = fread(fbuf, 1, sizeof(fbuf), fp)) > 0) - h->ops->hash(h, fbuf, sz); - h->ops->done(h, buf); - h->ops->destroy(h); + GH_HASH(h, fbuf, sz); + GH_DONE(h, buf); + GH_DESTROY(h); e = ferror(fp); if (file) fclose(fp); return (e ? -1 : 0); } -/* --- @puthex@ --- * - * - * Arguments: @const octet *buf@ = pointer to a binary buffer - * @size_t sz@ = size of the buffer - * @FILE *fp@ = pointer to output file handle - * - * Returns: --- - * - * Use: Writes a hex dump of a block of memory. - */ - -static void puthex(const octet *buf, size_t sz, FILE *fp) -{ - while (sz) { - fprintf(fp, "%02x", *buf++); - sz--; - } -} - -/* --- @gethex@ --- * - * - * Arguments: @const char *p@ = pointer to input string - * @octet *q@ = pointer to output buffer - * @size_t sz@ = size of the output buffer - * @char **pp@ = where to put the end pointer - * - * Returns: The number of bytes written to the buffer. - * - * Use: Reads hex dumps from the input string. - */ - -static size_t gethex(const char *p, octet *q, size_t sz, char **pp) -{ - size_t i = 0; - while (sz > 0 && - isxdigit((unsigned char)p[0]) && - isxdigit((unsigned char)p[1])) { - char buf[3]; - buf[0] = p[0]; - buf[1] = p[1]; - buf[2] = 0; - *q++ = strtoul(buf, 0, 16); - sz--; - p += 2; - i++; - } - if (pp) - *pp = (char *)p; - return (i); -} - /* --- @gethash@ --- * * * Arguments: @const char *name@ = pointer to name string @@ -186,9 +238,9 @@ static size_t gethex(const char *p, octet *q, size_t sz, char **pp) static const gchash *gethash(const char *name) { - const gchash **g, *gg = 0; + const gchash *const *g, *gg = 0; size_t sz = strlen(name); - for (g = hashtab; *g; g++) { + for (g = ghashtab; *g; g++) { if (strncmp(name, (*g)->name, sz) == 0) { if ((*g)->name[sz] == 0) { gg = *g; @@ -221,7 +273,7 @@ static int getstring(FILE *fp, const char *p, dstr *d, unsigned raw) /* --- Raw: just read exactly what's written up to a null byte --- */ -#define NEXTCH (fp ? getc(fp) : *p++) +#define NEXTCH (fp ? getc(fp) : (unsigned char)*p++) #define EOFCH (fp ? EOF : 0) if (raw) { @@ -245,7 +297,7 @@ static int getstring(FILE *fp, const char *p, dstr *d, unsigned raw) again: ch = NEXTCH; - while (isspace((unsigned char)ch)) + while (isspace(ch)) ch = NEXTCH; if (ch == '#') { do ch = NEXTCH; while (ch != '\n' && ch != EOFCH); @@ -294,7 +346,7 @@ again: if (ch == q) break; - if (!q && isspace((unsigned char)ch)) + if (!q && isspace(ch)) break; /* --- Otherwise contribute and continue --- */ @@ -379,7 +431,8 @@ static void putstring(FILE *fp, const char *p, unsigned raw) /*----- Guts --------------------------------------------------------------*/ -static int checkhash(const char *file, unsigned f, const gchash *gch) +static int checkhash(const char *file, unsigned f, + const gchash *gch, const encodeops *e) { int rc; FILE *fp; @@ -388,7 +441,7 @@ static int checkhash(const char *file, unsigned f, const gchash *gch) unsigned long n = 0, nfail = 0; octet *buf = xmalloc(2 * gch->hashsz); - if (!file) + if (!file || strcmp(file, "-") == 0) fp = stdin; else if ((fp = fopen(file, f & f_raw ? "r" : "rb")) == 0) { moan("couldn't open `%s': %s", file, strerror(errno)); @@ -415,6 +468,13 @@ static int checkhash(const char *file, unsigned f, const gchash *gch) gch = g; xfree(buf); buf = xmalloc(2 * gch->hashsz); + } else if (strcmp(q, "encoding") == 0) { + const encodeops *ee; + if ((q = str_getword(&p)) == 0) + continue; + if ((ee = getencoding(q)) == 0) + continue; + e = ee; } else if (strcmp(q, "escape") == 0) f |= f_escape; continue; @@ -422,18 +482,19 @@ static int checkhash(const char *file, unsigned f, const gchash *gch) /* --- Otherwise it's a hex thing --- */ - if ((q = str_getword(&p)) == 0) + q = p; + while (*p && *p != ' ') + p++; + if (!*p) continue; - if (gethex(q, buf, gch->hashsz, 0) < gch->hashsz) + *p++ = 0; + if (e->get(q, buf, gch->hashsz, 0) < gch->hashsz) continue; - while (isspace((unsigned char)*p)) - p++; - if (*p == '*') { - p++; + if (*p == '*') ff |= f_binary; - } - if (!*p) + else if (*p != ' ') continue; + p++; if (f & f_escape) { DRESET(&dd); @@ -470,7 +531,8 @@ static int checkhash(const char *file, unsigned f, const gchash *gch) return (0); } -static int dohash(const char *file, unsigned f, const gchash *gch) +static int dohash(const char *file, unsigned f, + const gchash *gch, const encodeops *e) { int rc = 0; octet *p = xmalloc(gch->hashsz); @@ -479,7 +541,7 @@ static int dohash(const char *file, unsigned f, const gchash *gch) moan("couldn't read `%s': %s", file ? file : "", strerror(errno)); rc = EXIT_FAILURE; } else { - puthex(p, gch->hashsz, stdout); + e->put(p, gch->hashsz, stdout); if (file) { fputc(' ', stdout); fputc(f & f_binary ? '*' : ' ', stdout); @@ -495,14 +557,21 @@ static int dohash(const char *file, unsigned f, const gchash *gch) return (rc); } -static int hashfiles(const char *file, unsigned f, const gchash *gch) +static int dofile(const char *file, unsigned f, + const gchash *gch, const encodeops *e) +{ + return (f & f_check ? checkhash : dohash)(file, f, gch, e); +} + +static int hashfiles(const char *file, unsigned f, + const gchash *gch, const encodeops *e) { FILE *fp; dstr d = DSTR_INIT; int rc = 0; int rrc; - if (!file) + if (!file || strcmp(file, "-") == 0) fp = stdin; else if ((fp = fopen(file, f & f_raw ? "r" : "rb")) == 0) { moan("couldn't open `%s': %s", file, strerror(errno)); @@ -513,32 +582,29 @@ static int hashfiles(const char *file, unsigned f, const gchash *gch) DRESET(&d); if (getstring(fp, 0, &d, f & f_raw)) break; - if ((rrc = dohash(d.buf, f, gch)) != 0) + if ((rrc = dofile(d.buf, f, gch, e)) != 0) rc = rrc; } return (rc); } -static int hashsum(const char *file, unsigned f, const gchash *gch) +static int hashsum(const char *file, unsigned f, + const gchash *gch, const encodeops *e) { - if (f & f_check) - return (checkhash(file, f, gch)); - if (f & f_files) - return (hashfiles(file, f, gch)); - return (dohash(file, f, gch)); + return (f & f_files ? hashfiles : dofile)(file, f, gch, e); } /*----- Main driver -------------------------------------------------------*/ -static void version(FILE *fp) +void version(FILE *fp) { pquis(fp, "$, Catacomb version " VERSION "\n"); } static void usage(FILE *fp) { - pquis(fp, "Usage: $ [-f0ebcv] [-a algorithm] [files...]\n"); + pquis(fp, "Usage: $ [-f0ebcv] [-a ALGORITHM] [-E ENC] [FILES...]\n"); } static void help(FILE *fp, const gchash *gch) @@ -552,8 +618,10 @@ Generates or checks message digests on files. Options available:\n\ -h, --help Display this help message.\n\ -V, --version Display program's version number.\n\ -u, --usage Display a terse usage message.\n\ +-l, --list [ITEM...] Show known hash functions and/or encodings.\n\ \n\ -a, --algorithm=ALG Use the message digest algorithm ALG.\n\ +-E, --encoding=ENC Represent hashes using encoding ENC.\n\ \n\ -f, --files Read a list of file names from standard input.\n\ -0, --null File names are null terminated, not plain text.\n\ @@ -563,16 +631,24 @@ Generates or checks message digests on files. Options available:\n\ -b, --binary When reading files, treat them as binary.\n\ -v, --verbose Be verbose when checking digests.\n\ \n\ -For a list of supported message digest algorithms, type `$ --list'.\n\ +For a list of hashing algorithms and encodings, type `$ --list'.\n\ "); if (gch) fprintf(fp, "The default message digest algorithm is %s.\n", gch->name); } +#define LISTS(LI) \ + LI("Lists", list, listtab[i].name, listtab[i].name) \ + LI("Hash functions", hash, ghashtab[i], ghashtab[i]->name) \ + LI("Encodings", enc, encodingtab[i].name, encodingtab[i].name) + +MAKELISTTAB(listtab, LISTS) + int main(int argc, char *argv[]) { unsigned f = 0; const gchash *gch = 0; + const encodeops *e = &encodingtab[0]; int rc; /* --- Initialization --- */ @@ -590,7 +666,7 @@ int main(int argc, char *argv[]) gch = gethash(q); } if (!gch) - gch = hashtab[0]; + gch = gethash("md5"); xfree(q); } @@ -604,6 +680,7 @@ int main(int argc, char *argv[]) { "algorithm", OPTF_ARGREQ, 0, 'a' }, { "hash", OPTF_ARGREQ, 0, 'a' }, + { "encoding", OPTF_ARGREQ, 0, 'E' }, { "list", 0, 0, 'l' }, { "files", 0, 0, 'f' }, @@ -617,7 +694,7 @@ int main(int argc, char *argv[]) { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "hVu a:l f0 ecbv", opts, 0, 0, 0); + int i = mdwopt(argc, argv, "hVu a:E:l f0 ecbv", opts, 0, 0, 0); if (i < 0) break; @@ -631,21 +708,18 @@ int main(int argc, char *argv[]) case 'u': usage(stdout); exit(0); + case 'l': + exit(displaylists(listtab, argv + optind)); case 'a': if ((gch = gethash(optarg)) == 0) die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg); f |= f_oddhash; break; - case 'l': { - unsigned j; - for (j = 0; hashtab[j]; j++) { - if (j) - fputc(' ', stdout); - printf("%s", hashtab[j]->name); - } - fputc('\n', stdout); - exit(0); - } break; + case 'E': + if ((e = getencoding(optarg)) == 0) + die(EXIT_FAILURE, "unknown encoding `%s'", optarg); + f |= f_oddenc; + break; case 'f': f |= f_files; break; @@ -679,23 +753,23 @@ int main(int argc, char *argv[]) /* --- Generate output --- */ - if (!(f & f_check)) { - if (f & f_oddhash) - printf("#hash %s\n", gch->name); - if (f & f_escape) - fputs("#escape\n", stdout); + if (!(f & f_check) && (argc || (f & f_files))) { + if (f & f_oddhash) printf("#hash %s\n", gch->name); + if (f & f_oddenc) printf("#encoding %s\n", e->name); + if (f & f_escape) fputs("#escape\n", stdout); } - - if (argc) { + if (!argc) + rc = hashsum(0, f, gch, e); + else { int i; int rrc; + rc = 0; for (i = 0; i < argc; i++) { - if ((rrc = hashsum(argv[i], f, gch)) != 0) + if ((rrc = hashsum(argv[i], f, gch, e)) != 0) rc = rrc; } - } else - rc = hashsum(0, f, gch); + } return (rc); }