md5.c revision 130351
16562Sphk/*
237421Scharnier * Derived from:
36562Sphk *
46562Sphk * MDDRIVER.C - test driver for MD2, MD4 and MD5
53995Spst */
63995Spst
76562Sphk/*
86562Sphk *  Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
96562Sphk *  rights reserved.
106562Sphk *
116562Sphk *  RSA Data Security, Inc. makes no representations concerning either
126562Sphk *  the merchantability of this software or the suitability of this
136562Sphk *  software for any particular purpose. It is provided "as is"
146562Sphk *  without express or implied warranty of any kind.
156562Sphk *
166562Sphk *  These notices must be retained in any copies of any part of this
176562Sphk *  documentation and/or software.
183995Spst */
193995Spst
20114589Sobrien#include <sys/cdefs.h>
21114589Sobrien__FBSDID("$FreeBSD: head/sbin/md5/md5.c 130351 2004-06-11 16:07:02Z eik $");
2237421Scharnier
2319168Sbde#include <sys/types.h>
24110840Ssilby#include <sys/time.h>
25110840Ssilby#include <sys/resource.h>
2637421Scharnier#include <err.h>
2719168Sbde#include <md5.h>
28130351Seik#include <ripemd.h>
29130351Seik#include <sha.h>
303995Spst#include <stdio.h>
3178949Sdes#include <stdlib.h>
3278949Sdes#include <string.h>
333995Spst#include <time.h>
3432074Ssteve#include <unistd.h>
3519168Sbde
366562Sphk/*
376562Sphk * Length of test block, number of test blocks.
383995Spst */
3946226Skris#define TEST_BLOCK_LEN 10000
4046226Skris#define TEST_BLOCK_COUNT 100000
41130351Seik#define MDTESTCOUNT 8
423995Spst
4354109Sobrienint qflag;
4452949Sobrienint rflag;
4588226Sphkint sflag;
4652949Sobrien
47130351Seiktypedef void (DIGEST_Init)(void *);
48130351Seiktypedef void (DIGEST_Update)(void *, const unsigned char *, size_t);
49130351Seiktypedef char *(DIGEST_End)(void *, char *);
503995Spst
51130351Seikextern const char *MD5TestOutput[MDTESTCOUNT];
52130351Seikextern const char *SHA1_TestOutput[MDTESTCOUNT];
53130351Seikextern const char *RIPEMD160_TestOutput[MDTESTCOUNT];
54130351Seik
55130351Seiktypedef struct Algorithm_t {
56130351Seik	const char *progname;
57130351Seik	const char *name;
58130351Seik	const char *(*TestOutput)[MDTESTCOUNT];
59130351Seik	DIGEST_Init *Init;
60130351Seik	DIGEST_Update *Update;
61130351Seik	DIGEST_End *End;
62130351Seik	char *(*Data)(const unsigned char *, unsigned int, char *);
63130351Seik	char *(*File)(const char *, char *);
64130351Seik} Algorithm_t;
65130351Seik
66130351Seikstatic void MD5_Update(MD5_CTX *, const unsigned char *, size_t);
67130351Seikstatic void MDString(Algorithm_t *, const char *);
68130351Seikstatic void MDTimeTrial(Algorithm_t *);
69130351Seikstatic void MDTestSuite(Algorithm_t *);
70130351Seikstatic void MDFilter(Algorithm_t *, int);
71130351Seikstatic void usage(Algorithm_t *);
72130351Seik
73130351Seiktypedef union {
74130351Seik	MD5_CTX md5;
75130351Seik	SHA1_CTX sha1;
76130351Seik	RIPEMD160_CTX ripemd160;
77130351Seik} DIGEST_CTX;
78130351Seik
79130351Seik/* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */
80130351Seik#define HEX_DIGEST_LENGTH 41
81130351Seik
82130351Seik/* algorithm function table */
83130351Seik
84130351Seikstruct Algorithm_t Algorithm[] = {
85130351Seik	{ "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init,
86130351Seik		(DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End,
87130351Seik		&MD5Data, &MD5File },
88130351Seik	{ "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init,
89130351Seik		(DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End,
90130351Seik		&SHA1_Data, &SHA1_File },
91130351Seik	{ "rmd160", "RMD160", &RIPEMD160_TestOutput,
92130351Seik		(DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update,
93130351Seik		(DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File }
94130351Seik};
95130351Seik
96130351Seikstatic void
97130351SeikMD5_Update(MD5_CTX *c, const unsigned char *data, size_t len)
98130351Seik{
99130351Seik	MD5Update(c, data, len);
100130351Seik}
101130351Seik
1023995Spst/* Main driver.
1033995Spst
1043995SpstArguments (may be any combination):
1053995Spst  -sstring - digests string
1063995Spst  -t       - runs time trial
1073995Spst  -x       - runs test script
1083995Spst  filename - digests file
1093995Spst  (none)   - digests standard input
1103995Spst */
1116562Sphkint
11276988Srumain(int argc, char *argv[])
1133995Spst{
11432086Ssteve	int     ch;
1156562Sphk	char   *p;
116130351Seik	char	buf[HEX_DIGEST_LENGTH];
117121914Sse	int     failed;
118130351Seik 	unsigned	digest;
119130351Seik 	const char*	progname;
120130351Seik
121130351Seik 	if ((progname = strrchr(argv[0], '/')) == NULL)
122130351Seik 		progname = argv[0];
123130351Seik 	else
124130351Seik 		progname++;
125130351Seik
126130351Seik 	for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++)
127130351Seik 		if (strcasecmp(Algorithm[digest].progname, progname) == 0)
128130351Seik 			break;
129130351Seik
130130351Seik 	if (Algorithm[digest].progname == NULL)
131130351Seik 		digest = 0;
1323995Spst
133121914Sse	failed = 0;
13478756Sru	while ((ch = getopt(argc, argv, "pqrs:tx")) != -1)
13576988Sru		switch (ch) {
13676988Sru		case 'p':
137130351Seik			MDFilter(&Algorithm[digest], 1);
13876988Sru			break;
13976988Sru		case 'q':
14076988Sru			qflag = 1;
14176988Sru			break;
14276988Sru		case 'r':
14376988Sru			rflag = 1;
14476988Sru			break;
14576988Sru		case 's':
14688226Sphk			sflag = 1;
147130351Seik			MDString(&Algorithm[digest], optarg);
14876988Sru			break;
14976988Sru		case 't':
150130351Seik			MDTimeTrial(&Algorithm[digest]);
15176988Sru			break;
15276988Sru		case 'x':
153130351Seik			MDTestSuite(&Algorithm[digest]);
15476988Sru			break;
15576988Sru		default:
156130351Seik			usage(&Algorithm[digest]);
15732074Ssteve		}
15876988Sru	argc -= optind;
15976988Sru	argv += optind;
16076988Sru
16176988Sru	if (*argv) {
16276988Sru		do {
163130351Seik			p = Algorithm[digest].File(*argv, buf);
164121914Sse			if (!p) {
16576988Sru				warn("%s", *argv);
166121914Sse				failed++;
167121914Sse			} else {
16854109Sobrien				if (qflag)
16954109Sobrien					printf("%s\n", p);
17054109Sobrien				else if (rflag)
17176988Sru					printf("%s %s\n", p, *argv);
17252949Sobrien				else
173130351Seik					printf("%s (%s) = %s\n", Algorithm[digest].name, *argv, p);
174121914Sse			}
17576988Sru		} while (*++argv);
17688226Sphk	} else if (!sflag && (optind == 1 || qflag || rflag))
177130351Seik		MDFilter(&Algorithm[digest], 0);
1783995Spst
179121914Sse	if (failed != 0)
180121914Sse		return (1);
181121914Sse
1826562Sphk	return (0);
1833995Spst}
1846562Sphk/*
1856562Sphk * Digests a string and prints the result.
1863995Spst */
1876562Sphkstatic void
188130351SeikMDString(Algorithm_t *alg, const char *string)
1893995Spst{
19048953Sbillf	size_t len = strlen(string);
191130351Seik	char buf[HEX_DIGEST_LENGTH];
1923995Spst
19354109Sobrien	if (qflag)
194130351Seik		printf("%s\n", alg->Data(string, len, buf));
19554109Sobrien	else if (rflag)
196130351Seik		printf("%s \"%s\"\n", alg->Data(string, len, buf), string);
19752949Sobrien	else
198130351Seik		printf("%s (\"%s\") = %s\n", alg->name, string, alg->Data(string, len, buf));
1993995Spst}
2006562Sphk/*
2016562Sphk * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
2023995Spst */
2036562Sphkstatic void
204130351SeikMDTimeTrial(Algorithm_t *alg)
2053995Spst{
206130351Seik	DIGEST_CTX context;
207110840Ssilby	struct rusage before, after;
208110840Ssilby	struct timeval total;
209110840Ssilby	float seconds;
2106725Sphk	unsigned char block[TEST_BLOCK_LEN];
2116562Sphk	unsigned int i;
212130351Seik	char   *p, buf[HEX_DIGEST_LENGTH];
2133995Spst
2146562Sphk	printf
215130351Seik	    ("%s time trial. Digesting %d %d-byte blocks ...",
216130351Seik	    alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
21746226Skris	fflush(stdout);
2183995Spst
2196562Sphk	/* Initialize block */
2206562Sphk	for (i = 0; i < TEST_BLOCK_LEN; i++)
2216562Sphk		block[i] = (unsigned char) (i & 0xff);
2223995Spst
2236562Sphk	/* Start timer */
224110840Ssilby	getrusage(0, &before);
2253995Spst
2266562Sphk	/* Digest blocks */
227130351Seik	alg->Init(&context);
2286562Sphk	for (i = 0; i < TEST_BLOCK_COUNT; i++)
229130351Seik		alg->Update(&context, block, TEST_BLOCK_LEN);
230130351Seik	p = alg->End(&context, buf);
2313995Spst
2326562Sphk	/* Stop timer */
233110840Ssilby	getrusage(0, &after);
234110840Ssilby	timersub(&after.ru_utime, &before.ru_utime, &total);
235110840Ssilby	seconds = total.tv_sec + (float) total.tv_usec / 1000000;
2363995Spst
2376562Sphk	printf(" done\n");
2386562Sphk	printf("Digest = %s", p);
239110840Ssilby	printf("\nTime = %f seconds\n", seconds);
2406562Sphk	printf
241110840Ssilby	    ("Speed = %f bytes/second\n",
242110840Ssilby	    (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds);
2433995Spst}
2446562Sphk/*
2456562Sphk * Digests a reference suite of strings and prints the results.
2463995Spst */
247109870Ssilby
248130351Seikconst char *MDTestInput[MDTESTCOUNT] = {
249109870Ssilby	"",
250109870Ssilby	"a",
251109870Ssilby	"abc",
252109870Ssilby	"message digest",
253109870Ssilby	"abcdefghijklmnopqrstuvwxyz",
254109870Ssilby	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
255109870Ssilby	"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
256130351Seik	"MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \
257130351Seikthat its security is in some doubt"
258109870Ssilby};
259109870Ssilby
260130351Seikconst char *MD5TestOutput[MDTESTCOUNT] = {
261109870Ssilby	"d41d8cd98f00b204e9800998ecf8427e",
262109870Ssilby	"0cc175b9c0f1b6a831c399e269772661",
263109870Ssilby	"900150983cd24fb0d6963f7d28e17f72",
264109870Ssilby	"f96b697d7cb7938d525a2f31aaf161d0",
265109870Ssilby	"c3fcd3d76192e4007dfb496cca67e13b",
266109870Ssilby	"d174ab98d277d9f5a5611c2c9f419d9f",
267109870Ssilby	"57edf4a22be3c955ac49da2e2107b67a",
268109870Ssilby	"b50663f41d44d92171cb9976bc118538"
269109870Ssilby};
270109870Ssilby
271130351Seikconst char *SHA1_TestOutput[MDTESTCOUNT] = {
272130351Seik	"da39a3ee5e6b4b0d3255bfef95601890afd80709",
273130351Seik	"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
274130351Seik	"a9993e364706816aba3e25717850c26c9cd0d89d",
275130351Seik	"c12252ceda8be8994d5fa0290a47231c1d16aae3",
276130351Seik	"32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
277130351Seik	"761c457bf73b14d27e9e9265c46f4b4dda11f940",
278130351Seik	"50abf5706a150990a08b2c5ea40fa0e585554732",
279130351Seik	"18eca4333979c4181199b7b4fab8786d16cf2846"
280130351Seik};
281130351Seik
282130351Seikconst char *RIPEMD160_TestOutput[MDTESTCOUNT] = {
283130351Seik	"9c1185a5c5e9fc54612808977ee8f548b2258d31",
284130351Seik	"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
285130351Seik	"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
286130351Seik	"5d0689ef49d2fae572b881b123a85ffa21595f36",
287130351Seik	"f71c27109c692c1b56bbdceb5b9d2865b3708dbc",
288130351Seik	"b0e20b6e3116640286ed3a87a5713079b21f5189",
289130351Seik	"9b752e45573d4b39f4dbd3323cab82bf63326bfb",
290130351Seik	"5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32"
291130351Seik};
292130351Seik
2936562Sphkstatic void
294130351SeikMDTestSuite(Algorithm_t *alg)
2953995Spst{
296109870Ssilby	int i;
297130351Seik	char buffer[HEX_DIGEST_LENGTH];
29832086Ssteve
299130351Seik	printf("%s test suite:\n", alg->name);
300130351Seik	for (i = 0; i < MDTESTCOUNT; i++) {
301130351Seik		(*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer);
302130351Seik		printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer);
303130351Seik		if (strcmp(buffer, (*alg->TestOutput)[i]) == 0)
304109870Ssilby			printf(" - verified correct\n");
305109870Ssilby		else
306109870Ssilby			printf(" - INCORRECT RESULT!\n");
307109870Ssilby	}
3083995Spst}
3093995Spst
3106562Sphk/*
3116562Sphk * Digests the standard input and prints the result.
3123995Spst */
3136562Sphkstatic void
314130351SeikMDFilter(Algorithm_t *alg, int tee)
3153995Spst{
316130351Seik	DIGEST_CTX context;
31776988Sru	unsigned int len;
31832074Ssteve	unsigned char buffer[BUFSIZ];
319130351Seik	char buf[HEX_DIGEST_LENGTH];
3203995Spst
321130351Seik	alg->Init(&context);
32232074Ssteve	while ((len = fread(buffer, 1, BUFSIZ, stdin))) {
32376988Sru		if (tee && len != fwrite(buffer, 1, len, stdout))
32437421Scharnier			err(1, "stdout");
325130351Seik		alg->Update(&context, buffer, len);
3266725Sphk	}
327130351Seik	printf("%s\n", alg->End(&context, buf));
3283995Spst}
32932074Ssteve
33032074Sstevestatic void
331130351Seikusage(Algorithm_t *alg)
33232074Ssteve{
33332086Ssteve
334130351Seik	fprintf(stderr, "usage: %s [-pqrtx] [-s string] [files ...]\n", alg->progname);
33532074Ssteve	exit(1);
33632074Ssteve}
337