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$");
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>
30143334Scperciva#include <sha256.h>
313995Spst#include <stdio.h>
3278949Sdes#include <stdlib.h>
3378949Sdes#include <string.h>
343995Spst#include <time.h>
3532074Ssteve#include <unistd.h>
3619168Sbde
376562Sphk/*
386562Sphk * Length of test block, number of test blocks.
393995Spst */
4046226Skris#define TEST_BLOCK_LEN 10000
4146226Skris#define TEST_BLOCK_COUNT 100000
42130351Seik#define MDTESTCOUNT 8
433995Spst
4454109Sobrienint qflag;
4552949Sobrienint rflag;
4688226Sphkint sflag;
47229680Seadlerunsigned char* checkAgainst;
48229680Seadlerint	checksFailed;
4952949Sobrien
50130351Seiktypedef void (DIGEST_Init)(void *);
51130351Seiktypedef void (DIGEST_Update)(void *, const unsigned char *, size_t);
52130351Seiktypedef char *(DIGEST_End)(void *, char *);
533995Spst
54130351Seikextern const char *MD5TestOutput[MDTESTCOUNT];
55130351Seikextern const char *SHA1_TestOutput[MDTESTCOUNT];
56143334Scpercivaextern const char *SHA256_TestOutput[MDTESTCOUNT];
57130351Seikextern const char *RIPEMD160_TestOutput[MDTESTCOUNT];
58130351Seik
59130351Seiktypedef struct Algorithm_t {
60130351Seik	const char *progname;
61130351Seik	const char *name;
62130351Seik	const char *(*TestOutput)[MDTESTCOUNT];
63130351Seik	DIGEST_Init *Init;
64130351Seik	DIGEST_Update *Update;
65130351Seik	DIGEST_End *End;
66154479Sphk	char *(*Data)(const void *, unsigned int, char *);
67130351Seik	char *(*File)(const char *, char *);
68130351Seik} Algorithm_t;
69130351Seik
70130351Seikstatic void MD5_Update(MD5_CTX *, const unsigned char *, size_t);
71130351Seikstatic void MDString(Algorithm_t *, const char *);
72130351Seikstatic void MDTimeTrial(Algorithm_t *);
73130351Seikstatic void MDTestSuite(Algorithm_t *);
74130351Seikstatic void MDFilter(Algorithm_t *, int);
75130351Seikstatic void usage(Algorithm_t *);
76130351Seik
77130351Seiktypedef union {
78130351Seik	MD5_CTX md5;
79130351Seik	SHA1_CTX sha1;
80143334Scperciva	SHA256_CTX sha256;
81130351Seik	RIPEMD160_CTX ripemd160;
82130351Seik} DIGEST_CTX;
83130351Seik
84176095Sobrien/* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
85239937Sdelphij	SHA256_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */
86239937Sdelphij#define HEX_DIGEST_LENGTH 65
87130351Seik
88130351Seik/* algorithm function table */
89130351Seik
90130351Seikstruct Algorithm_t Algorithm[] = {
91130351Seik	{ "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init,
92130351Seik		(DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End,
93130351Seik		&MD5Data, &MD5File },
94130351Seik	{ "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init,
95130351Seik		(DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End,
96130351Seik		&SHA1_Data, &SHA1_File },
97143334Scperciva	{ "sha256", "SHA256", &SHA256_TestOutput, (DIGEST_Init*)&SHA256_Init,
98143334Scperciva		(DIGEST_Update*)&SHA256_Update, (DIGEST_End*)&SHA256_End,
99143334Scperciva		&SHA256_Data, &SHA256_File },
100130351Seik	{ "rmd160", "RMD160", &RIPEMD160_TestOutput,
101130351Seik		(DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update,
102130351Seik		(DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File }
103130351Seik};
104130351Seik
105130351Seikstatic void
106130351SeikMD5_Update(MD5_CTX *c, const unsigned char *data, size_t len)
107130351Seik{
108130351Seik	MD5Update(c, data, len);
109130351Seik}
110130351Seik
1113995Spst/* Main driver.
1123995Spst
1133995SpstArguments (may be any combination):
1143995Spst  -sstring - digests string
1153995Spst  -t       - runs time trial
1163995Spst  -x       - runs test script
1173995Spst  filename - digests file
1183995Spst  (none)   - digests standard input
1193995Spst */
1206562Sphkint
12176988Srumain(int argc, char *argv[])
1223995Spst{
123176095Sobrien	int	ch;
1246562Sphk	char   *p;
125130351Seik	char	buf[HEX_DIGEST_LENGTH];
126176095Sobrien	int	failed;
127130351Seik 	unsigned	digest;
128130351Seik 	const char*	progname;
129176095Sobrien
130130351Seik 	if ((progname = strrchr(argv[0], '/')) == NULL)
131130351Seik 		progname = argv[0];
132130351Seik 	else
133130351Seik 		progname++;
134176095Sobrien
135130351Seik 	for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++)
136130351Seik 		if (strcasecmp(Algorithm[digest].progname, progname) == 0)
137130351Seik 			break;
138176095Sobrien
139130918Seik 	if (digest == sizeof(Algorithm)/sizeof(*Algorithm))
140130351Seik 		digest = 0;
1413995Spst
142121914Sse	failed = 0;
143229680Seadler	checkAgainst = NULL;
144229680Seadler	checksFailed = 0;
145229680Seadler	while ((ch = getopt(argc, argv, "c:pqrs:tx")) != -1)
14676988Sru		switch (ch) {
147229680Seadler		case 'c':
148229680Seadler			checkAgainst = optarg;
149229680Seadler			break;
15076988Sru		case 'p':
151130351Seik			MDFilter(&Algorithm[digest], 1);
15276988Sru			break;
15376988Sru		case 'q':
15476988Sru			qflag = 1;
15576988Sru			break;
15676988Sru		case 'r':
15776988Sru			rflag = 1;
15876988Sru			break;
15976988Sru		case 's':
16088226Sphk			sflag = 1;
161130351Seik			MDString(&Algorithm[digest], optarg);
16276988Sru			break;
16376988Sru		case 't':
164130351Seik			MDTimeTrial(&Algorithm[digest]);
16576988Sru			break;
16676988Sru		case 'x':
167130351Seik			MDTestSuite(&Algorithm[digest]);
16876988Sru			break;
16976988Sru		default:
170130351Seik			usage(&Algorithm[digest]);
17132074Ssteve		}
17276988Sru	argc -= optind;
17376988Sru	argv += optind;
17476988Sru
17576988Sru	if (*argv) {
17676988Sru		do {
177130351Seik			p = Algorithm[digest].File(*argv, buf);
178121914Sse			if (!p) {
17976988Sru				warn("%s", *argv);
180121914Sse				failed++;
181121914Sse			} else {
18254109Sobrien				if (qflag)
183229680Seadler					printf("%s", p);
18454109Sobrien				else if (rflag)
185229680Seadler					printf("%s %s", p, *argv);
18652949Sobrien				else
187229680Seadler					printf("%s (%s) = %s",
188176095Sobrien					    Algorithm[digest].name, *argv, p);
189229680Seadler				if (checkAgainst && strcmp(checkAgainst,p))
190229680Seadler				{
191229680Seadler					checksFailed++;
192229680Seadler					if (!qflag)
193229680Seadler						printf(" [ Failed ]");
194229680Seadler				}
195229680Seadler				printf("\n");
196121914Sse			}
19776988Sru		} while (*++argv);
19888226Sphk	} else if (!sflag && (optind == 1 || qflag || rflag))
199130351Seik		MDFilter(&Algorithm[digest], 0);
2003995Spst
201121914Sse	if (failed != 0)
202121914Sse		return (1);
203229680Seadler	if (checksFailed != 0)
204229680Seadler		return (2);
205176095Sobrien
2066562Sphk	return (0);
2073995Spst}
2086562Sphk/*
2096562Sphk * Digests a string and prints the result.
2103995Spst */
2116562Sphkstatic void
212130351SeikMDString(Algorithm_t *alg, const char *string)
2133995Spst{
21448953Sbillf	size_t len = strlen(string);
215130351Seik	char buf[HEX_DIGEST_LENGTH];
2163995Spst
217229680Seadler	alg->Data(string,len,buf);
21854109Sobrien	if (qflag)
219229680Seadler		printf("%s", buf);
22054109Sobrien	else if (rflag)
221229680Seadler		printf("%s \"%s\"", buf, string);
22252949Sobrien	else
223229680Seadler		printf("%s (\"%s\") = %s", alg->name, string, buf);
224229680Seadler	if (checkAgainst && strcmp(buf,checkAgainst))
225229680Seadler	{
226229680Seadler		checksFailed++;
227229680Seadler		if (!qflag)
228229680Seadler			printf(" [ failed ]");
229229680Seadler	}
230229680Seadler	printf("\n");
2313995Spst}
2326562Sphk/*
2336562Sphk * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
2343995Spst */
2356562Sphkstatic void
236130351SeikMDTimeTrial(Algorithm_t *alg)
2373995Spst{
238130351Seik	DIGEST_CTX context;
239110840Ssilby	struct rusage before, after;
240110840Ssilby	struct timeval total;
241110840Ssilby	float seconds;
2426725Sphk	unsigned char block[TEST_BLOCK_LEN];
2436562Sphk	unsigned int i;
244176095Sobrien	char *p, buf[HEX_DIGEST_LENGTH];
2453995Spst
246176095Sobrien	printf("%s time trial. Digesting %d %d-byte blocks ...",
247130351Seik	    alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
24846226Skris	fflush(stdout);
2493995Spst
2506562Sphk	/* Initialize block */
2516562Sphk	for (i = 0; i < TEST_BLOCK_LEN; i++)
2526562Sphk		block[i] = (unsigned char) (i & 0xff);
2533995Spst
2546562Sphk	/* Start timer */
255182672Skevlo	getrusage(RUSAGE_SELF, &before);
2563995Spst
2576562Sphk	/* Digest blocks */
258130351Seik	alg->Init(&context);
2596562Sphk	for (i = 0; i < TEST_BLOCK_COUNT; i++)
260130351Seik		alg->Update(&context, block, TEST_BLOCK_LEN);
261130351Seik	p = alg->End(&context, buf);
2623995Spst
2636562Sphk	/* Stop timer */
264182672Skevlo	getrusage(RUSAGE_SELF, &after);
265110840Ssilby	timersub(&after.ru_utime, &before.ru_utime, &total);
266110840Ssilby	seconds = total.tv_sec + (float) total.tv_usec / 1000000;
2673995Spst
2686562Sphk	printf(" done\n");
2696562Sphk	printf("Digest = %s", p);
270110840Ssilby	printf("\nTime = %f seconds\n", seconds);
271176095Sobrien	printf("Speed = %f bytes/second\n",
272110840Ssilby	    (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds);
2733995Spst}
2746562Sphk/*
2756562Sphk * Digests a reference suite of strings and prints the results.
2763995Spst */
277109870Ssilby
278130351Seikconst char *MDTestInput[MDTESTCOUNT] = {
279176095Sobrien	"",
280109870Ssilby	"a",
281109870Ssilby	"abc",
282109870Ssilby	"message digest",
283109870Ssilby	"abcdefghijklmnopqrstuvwxyz",
284109870Ssilby	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
285109870Ssilby	"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
286130351Seik	"MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \
287130351Seikthat its security is in some doubt"
288109870Ssilby};
289109870Ssilby
290130351Seikconst char *MD5TestOutput[MDTESTCOUNT] = {
291109870Ssilby	"d41d8cd98f00b204e9800998ecf8427e",
292109870Ssilby	"0cc175b9c0f1b6a831c399e269772661",
293109870Ssilby	"900150983cd24fb0d6963f7d28e17f72",
294109870Ssilby	"f96b697d7cb7938d525a2f31aaf161d0",
295109870Ssilby	"c3fcd3d76192e4007dfb496cca67e13b",
296109870Ssilby	"d174ab98d277d9f5a5611c2c9f419d9f",
297109870Ssilby	"57edf4a22be3c955ac49da2e2107b67a",
298109870Ssilby	"b50663f41d44d92171cb9976bc118538"
299109870Ssilby};
300109870Ssilby
301130351Seikconst char *SHA1_TestOutput[MDTESTCOUNT] = {
302130351Seik	"da39a3ee5e6b4b0d3255bfef95601890afd80709",
303130351Seik	"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
304130351Seik	"a9993e364706816aba3e25717850c26c9cd0d89d",
305130351Seik	"c12252ceda8be8994d5fa0290a47231c1d16aae3",
306130351Seik	"32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
307130351Seik	"761c457bf73b14d27e9e9265c46f4b4dda11f940",
308130351Seik	"50abf5706a150990a08b2c5ea40fa0e585554732",
309130351Seik	"18eca4333979c4181199b7b4fab8786d16cf2846"
310130351Seik};
311130351Seik
312143334Scpercivaconst char *SHA256_TestOutput[MDTESTCOUNT] = {
313143334Scperciva	"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
314143334Scperciva	"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
315143334Scperciva	"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
316143334Scperciva	"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650",
317143334Scperciva	"71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73",
318143334Scperciva	"db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0",
319143334Scperciva	"f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e",
320143334Scperciva	"e6eae09f10ad4122a0e2a4075761d185a272ebd9f5aa489e998ff2f09cbfdd9f"
321143334Scperciva};
322143334Scperciva
323130351Seikconst char *RIPEMD160_TestOutput[MDTESTCOUNT] = {
324130351Seik	"9c1185a5c5e9fc54612808977ee8f548b2258d31",
325130351Seik	"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
326130351Seik	"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
327130351Seik	"5d0689ef49d2fae572b881b123a85ffa21595f36",
328130351Seik	"f71c27109c692c1b56bbdceb5b9d2865b3708dbc",
329130351Seik	"b0e20b6e3116640286ed3a87a5713079b21f5189",
330130351Seik	"9b752e45573d4b39f4dbd3323cab82bf63326bfb",
331130351Seik	"5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32"
332130351Seik};
333130351Seik
3346562Sphkstatic void
335130351SeikMDTestSuite(Algorithm_t *alg)
3363995Spst{
337109870Ssilby	int i;
338130351Seik	char buffer[HEX_DIGEST_LENGTH];
33932086Ssteve
340130351Seik	printf("%s test suite:\n", alg->name);
341130351Seik	for (i = 0; i < MDTESTCOUNT; i++) {
342130351Seik		(*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer);
343130351Seik		printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer);
344130351Seik		if (strcmp(buffer, (*alg->TestOutput)[i]) == 0)
345109870Ssilby			printf(" - verified correct\n");
346109870Ssilby		else
347109870Ssilby			printf(" - INCORRECT RESULT!\n");
348109870Ssilby	}
3493995Spst}
3503995Spst
3516562Sphk/*
3526562Sphk * Digests the standard input and prints the result.
3533995Spst */
3546562Sphkstatic void
355130351SeikMDFilter(Algorithm_t *alg, int tee)
3563995Spst{
357130351Seik	DIGEST_CTX context;
35876988Sru	unsigned int len;
35932074Ssteve	unsigned char buffer[BUFSIZ];
360130351Seik	char buf[HEX_DIGEST_LENGTH];
3613995Spst
362130351Seik	alg->Init(&context);
36332074Ssteve	while ((len = fread(buffer, 1, BUFSIZ, stdin))) {
36476988Sru		if (tee && len != fwrite(buffer, 1, len, stdout))
36537421Scharnier			err(1, "stdout");
366130351Seik		alg->Update(&context, buffer, len);
3676725Sphk	}
368130351Seik	printf("%s\n", alg->End(&context, buf));
3693995Spst}
37032074Ssteve
37132074Sstevestatic void
372130351Seikusage(Algorithm_t *alg)
37332074Ssteve{
37432086Ssteve
375235309Seadler	fprintf(stderr, "usage: %s [-pqrtx] [-c string] [-s string] [files ...]\n", alg->progname);
37632074Ssteve	exit(1);
37732074Ssteve}
378