diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2001-06-02 20:38:07 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2001-06-02 20:38:07 +0000 |
commit | 21e0f36c9bdc0f56c027ed3a3c3c5e5dadd63750 (patch) | |
tree | 3c02e238a8c828678be35a3a861e95584f1d5e13 /bin/md5/md5.c | |
parent | 7619b95668c07181ff18319b929210af7198af27 (diff) |
New md5/sha1/rmd160 driver with a BSD copyright. Improvements:
o options that should be mutually exclusive are
o time trial works reasonably when it finishes in < 1 sec
o uses a function table instead of a bunch of globals
Diffstat (limited to 'bin/md5/md5.c')
-rw-r--r-- | bin/md5/md5.c | 393 |
1 files changed, 199 insertions, 194 deletions
diff --git a/bin/md5/md5.c b/bin/md5/md5.c index 8717c2e5b3c..b2fb04c2c49 100644 --- a/bin/md5/md5.c +++ b/bin/md5/md5.c @@ -1,243 +1,248 @@ -/* - * $OpenBSD: md5.c,v 1.9 1999/10/07 16:56:33 espie Exp $ - * - * Derived from: - * MDDRIVER.C - test driver for MD2, MD4 and MD5 - */ +/* $OpenBSD: md5.c,v 1.10 2001/06/02 20:38:06 millert Exp $ */ /* - * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All - * rights reserved. + * Copyright (c) 2001 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. * - * RSA Data Security, Inc. makes no representations concerning either - * the merchantability of this software or the suitability of this - * software for any particular purpose. It is provided "as is" - * without express or implied warranty of any kind. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. * - * These notices must be retained in any copies of any part of this - * documentation and/or software. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/param.h> #include <err.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> -#include <time.h> #include <string.h> +#include <time.h> +#include <unistd.h> #include <md5.h> #include <sha1.h> #include <rmd160.h> -/* - * Length of test block, number of test blocks. - */ -#define TEST_BLOCK_LEN 10000 -#define TEST_BLOCK_COUNT 10000 +#define DIGEST_MD5 0 +#define DIGEST_SHA1 1 +#define DIGEST_RMD160 2 union ANY_CTX { - RMD160_CTX a; - SHA1_CTX b; - MD5_CTX c; + MD5_CTX md5; + SHA1_CTX sha1; + RMD160_CTX rmd160; }; -extern char *__progname; +struct hash_functions { + char *name; + void (*init)(); + void (*update)(); + char * (*end)(); + char * (*file)(); + char * (*data)(); +}; +struct hash_functions functions[] = { + { + "MD5", + MD5Init, MD5Update, MD5End, MD5File, MD5Data + }, { + "SHA1", + SHA1Init, SHA1Update, SHA1End, SHA1File, SHA1Data + }, { + "RMD160", + RMD160Init, RMD160Update, RMD160End, RMD160File, RMD160Data + }, +}; -static void MDString __P((char *)); -static void MDTimeTrial __P((void *)); -static void MDTestSuite __P((void)); -static void MDFilter __P((int, void *)); -static void usage __P((char *)); +extern char *__progname; +static void usage(void); +static void digest_file(char *, struct hash_functions *, int); +static void digest_string(char *, struct hash_functions *); +static void digest_test(struct hash_functions *); +static void digest_time(struct hash_functions *); -/* - * Globals for indirection... - */ -void (*MDInit)(); -void (*MDUpdate)(); -char * (*MDEnd)(); -char * (*MDFile)(); -char * (*MDData)(); -char *MDType; - -/* Main driver. - * - * Arguments (may be any combination): - * -sstring - digests string - * -t - runs time trial - * -x - runs test script - * filename - digests file - * (none) - digests standard input - */ int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char **argv) { - int ch; - char *p; - char buf[41]; - void *context; - - if ((context = malloc(sizeof(union ANY_CTX))) == NULL) - err(1, "malloc"); - - /* What were we called as? Default to md5 */ - if (strcmp(__progname, "rmd160") == 0) { - MDType = "RMD160"; - MDInit = RMD160Init; - MDUpdate = RMD160Update; - MDEnd = RMD160End; - MDFile = RMD160File; - MDData = RMD160Data; - } else if (strcmp(__progname, "sha1") == 0) { - MDType = "SHA1"; - MDInit = SHA1Init; - MDUpdate = SHA1Update; - MDEnd = SHA1End; - MDFile = SHA1File; - MDData = SHA1Data; - } else { - MDType = "MD5"; - MDInit = MD5Init; - MDUpdate = MD5Update; - MDEnd = MD5End; - MDFile = MD5File; - MDData = MD5Data; - } - - if (argc > 1) { - while ((ch = getopt(argc, argv, "ps:tx")) != -1) { - switch (ch) { - case 'p': - MDFilter(1, context); - break; - case 's': - MDString(optarg); - break; - case 't': - MDTimeTrial(context); - break; - case 'x': - MDTestSuite(); - break; - default: - usage(MDType); - } + int ch, digest_type; + int pflag, tflag, xflag; + char *input_string; + + /* Set digest type based on program name, defaults to MD5. */ + if (strcmp(__progname, "rmd160") == 0) + digest_type = DIGEST_RMD160; + else if (strcmp(__progname, "sha1") == 0) + digest_type = DIGEST_SHA1; + else + digest_type = DIGEST_MD5; + + input_string = NULL; + pflag = tflag = xflag = 0; + while ((ch = getopt(argc, argv, "ps:tx")) != -1) { + switch (ch) { + case 'p': + pflag = 1; + break; + case 's': + input_string = optarg; + break; + case 't': + tflag = 1; + break; + case 'x': + xflag = 1; + break; + default: + usage(); } - while (optind < argc) { - p = MDFile(argv[optind], buf); - if (!p) - perror(argv[optind]); - else - printf("%s (%s) = %s\n", MDType, - argv[optind], p); - optind++; - } - } else - MDFilter(0, context); + } + argc -= optind; + argv += optind; + + if (pflag + tflag + xflag + argc > 1) + usage(); + + if (tflag) + digest_time(&functions[digest_type]); + else if (xflag) + digest_test(&functions[digest_type]); + else if (input_string) + digest_string(input_string, &functions[digest_type]); + else if (pflag || argc == 0) + digest_file("-", &functions[digest_type], pflag); + else + while (argc--) + digest_file(*argv++, &functions[digest_type], 0); exit(0); } -/* - * Digests a string and prints the result. - */ + static void -MDString(string) - char *string; +digest_string(char *string, struct hash_functions *hf) { - size_t len = strlen(string); - char buf[41]; + char *digtest; - (void)printf("%s (\"%s\") = %s\n", MDType, string, - MDData(string, len, buf)); + digtest = hf->data(string, strlen(string), NULL); + (void)printf("%s (\"%s\") = %s\n", hf->name, string, digtest); + free(digtest); } -/* - * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. - */ + static void -MDTimeTrial(context) - void *context; +digest_file(char *file, struct hash_functions *hf, int echo) { - time_t endTime, startTime; - unsigned char block[TEST_BLOCK_LEN]; - unsigned int i; - char *p, buf[41]; - - (void)printf("%s time trial. Digesting %d %d-byte blocks ...", MDType, - TEST_BLOCK_LEN, TEST_BLOCK_COUNT); - fflush(stdout); + int fd; + ssize_t nread; + u_char data[BUFSIZ]; + char *digest; + union ANY_CTX context; + + if (strcmp(file, "-") == 0) + fd = STDIN_FILENO; + else if ((fd = open(file, O_RDONLY, 0)) == -1) { + warn("cannot open %s", file); + return; + } - /* Initialize block */ - for (i = 0; i < TEST_BLOCK_LEN; i++) - block[i] = (unsigned char) (i & 0xff); + if (echo) + fflush(stdout); - /* Start timer */ - time(&startTime); + hf->init(&context); + while ((nread = read(fd, data, sizeof(data))) > 0) { + if (echo) + write(STDOUT_FILENO, data, (size_t)nread); + hf->update(&context, data, nread); + } + digest = hf->end(&context, NULL); - /* Digest blocks */ - MDInit(context); - for (i = 0; i < TEST_BLOCK_COUNT; i++) - MDUpdate(context, block, (size_t)TEST_BLOCK_LEN); - p = MDEnd(context,buf); - - /* Stop timer */ - time(&endTime); - - (void)printf(" done\nDigest = %s", p); - (void)printf("\nTime = %ld seconds\n", (long) (endTime - startTime)); - /* - * Be careful that endTime-startTime is not zero. - * (Bug fix from Ric Anderson <ric@Artisoft.COM>) - */ - (void)printf("Speed = %ld bytes/second\n", - (long) TEST_BLOCK_LEN * (long) TEST_BLOCK_COUNT / - ((endTime - startTime) != 0 ? (endTime - startTime) : 1)); + if (fd == STDIN_FILENO) { + (void)puts(digest); + } else { + close(fd); + (void)printf("%s (%s) = %s\n", hf->name, file, digest); + } + free(digest); } -/* - * Digests a reference suite of strings and prints the results. - */ + +#define TEST_BLOCK_LEN 10000 +#define TEST_BLOCK_COUNT 10000 + static void -MDTestSuite() +digest_time(struct hash_functions *hf) { - (void)printf("%s test suite:\n", MDType); - - MDString(""); - MDString("a"); - MDString("abc"); - MDString("message digest"); - MDString("abcdefghijklmnopqrstuvwxyz"); - MDString - ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); - MDString - ("1234567890123456789012345678901234567890\ -1234567890123456789012345678901234567890"); - MDString("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + struct timeval start, stop, res; + union ANY_CTX context; + u_int i; + u_char data[TEST_BLOCK_LEN]; + char *digest; + double elapsed; + + (void)printf("%s time trial. Processing %d %d-byte blocks...", + hf->name, TEST_BLOCK_LEN, TEST_BLOCK_COUNT); + fflush(stdout); + + /* Initialize data based on block number. */ + for (i = 0; i < TEST_BLOCK_LEN; i++) + data[i] = (u_char)(i & 0xff); + + gettimeofday(&start, NULL); + hf->init(&context); + for (i = 0; i < TEST_BLOCK_COUNT; i++) + hf->update(&context, data, TEST_BLOCK_LEN); + digest = hf->end(&context, NULL); + gettimeofday(&stop, NULL); + timersub(&stop, &start, &res); + elapsed = res.tv_sec + res.tv_usec / 1000000.0; + + (void)printf("\nDigest = %s\n", digest); + (void)printf("Time = %f seconds\n", elapsed); + (void)printf("Speed = %f bytes/second\n", + TEST_BLOCK_LEN * TEST_BLOCK_COUNT / elapsed); + free(digest); } -/* - * Digests the standard input and prints the result. - */ static void -MDFilter(pipe, context) - int pipe; - void *context; +digest_test(struct hash_functions *hf) { - size_t len; - unsigned char buffer[BUFSIZ]; - char buf[41]; - - MDInit(context); - while ((len = fread(buffer, (size_t)1, (size_t)BUFSIZ, stdin)) > 0) { - if (pipe && (len != fwrite(buffer, (size_t)1, len, stdout))) - err(1, "stdout"); - MDUpdate(context, buffer, len); - } - (void)printf("%s\n", MDEnd(context,buf)); + + /* XXX - different test data for different hashes? */ + (void)printf("%s test suite:\n", hf->name); + + /* MD5 test suite as per RFC 1321 */ + digest_string("", hf); + digest_string("a", hf); + digest_string("abc", hf); + digest_string("message digest", hf); + digest_string("abcdefghijklmnopqrstuvwxyz", hf); + digest_string("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789", hf); + digest_string("1234567890123456789012345678901234567890123456789" + "0123456789012345678901234567890", hf); + digest_string("abcdbcdecdefdefgefghfghighijhijkijkljklmklmn" + "lmnomnopnopq", hf); } static void -usage(type) -char *type; +usage() { - fprintf(stderr, "usage: %s [-ptx] [-s string] [file ...]\n", type); + + fprintf(stderr, "usage: %s [-p | -t | -x | -s string | file ...]\n", + __progname); exit(1); } |