summaryrefslogtreecommitdiff
path: root/bin/md5
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2001-06-02 20:38:07 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2001-06-02 20:38:07 +0000
commit21e0f36c9bdc0f56c027ed3a3c3c5e5dadd63750 (patch)
tree3c02e238a8c828678be35a3a861e95584f1d5e13 /bin/md5
parent7619b95668c07181ff18319b929210af7198af27 (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')
-rw-r--r--bin/md5/md5.c393
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);
}