md5.c revision 176095
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 176095 2008-02-07 18:10:24Z obrien $");
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;
4752949Sobrien
48130351Seiktypedef void (DIGEST_Init)(void *);
49130351Seiktypedef void (DIGEST_Update)(void *, const unsigned char *, size_t);
50130351Seiktypedef char *(DIGEST_End)(void *, char *);
513995Spst
52130351Seikextern const char *MD5TestOutput[MDTESTCOUNT];
53130351Seikextern const char *SHA1_TestOutput[MDTESTCOUNT];
54143334Scpercivaextern const char *SHA256_TestOutput[MDTESTCOUNT];
55130351Seikextern const char *RIPEMD160_TestOutput[MDTESTCOUNT];
56130351Seik
57130351Seiktypedef struct Algorithm_t {
58130351Seik	const char *progname;
59130351Seik	const char *name;
60130351Seik	const char *(*TestOutput)[MDTESTCOUNT];
61130351Seik	DIGEST_Init *Init;
62130351Seik	DIGEST_Update *Update;
63130351Seik	DIGEST_End *End;
64154479Sphk	char *(*Data)(const void *, unsigned int, char *);
65130351Seik	char *(*File)(const char *, char *);
66130351Seik} Algorithm_t;
67130351Seik
68130351Seikstatic void MD5_Update(MD5_CTX *, const unsigned char *, size_t);
69130351Seikstatic void MDString(Algorithm_t *, const char *);
70130351Seikstatic void MDTimeTrial(Algorithm_t *);
71130351Seikstatic void MDTestSuite(Algorithm_t *);
72130351Seikstatic void MDFilter(Algorithm_t *, int);
73130351Seikstatic void usage(Algorithm_t *);
74130351Seik
75130351Seiktypedef union {
76130351Seik	MD5_CTX md5;
77130351Seik	SHA1_CTX sha1;
78143334Scperciva	SHA256_CTX sha256;
79130351Seik	RIPEMD160_CTX ripemd160;
80130351Seik} DIGEST_CTX;
81130351Seik
82176095Sobrien/* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
83143334Scperciva	SHA256_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */
84143334Scperciva#define HEX_DIGEST_LENGTH 65
85130351Seik
86130351Seik/* algorithm function table */
87130351Seik
88130351Seikstruct Algorithm_t Algorithm[] = {
89130351Seik	{ "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init,
90130351Seik		(DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End,
91130351Seik		&MD5Data, &MD5File },
92130351Seik	{ "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init,
93130351Seik		(DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End,
94130351Seik		&SHA1_Data, &SHA1_File },
95143334Scperciva	{ "sha256", "SHA256", &SHA256_TestOutput, (DIGEST_Init*)&SHA256_Init,
96143334Scperciva		(DIGEST_Update*)&SHA256_Update, (DIGEST_End*)&SHA256_End,
97143334Scperciva		&SHA256_Data, &SHA256_File },
98130351Seik	{ "rmd160", "RMD160", &RIPEMD160_TestOutput,
99130351Seik		(DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update,
100130351Seik		(DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File }
101130351Seik};
102130351Seik
103130351Seikstatic void
104130351SeikMD5_Update(MD5_CTX *c, const unsigned char *data, size_t len)
105130351Seik{
106130351Seik	MD5Update(c, data, len);
107130351Seik}
108130351Seik
1093995Spst/* Main driver.
1103995Spst
1113995SpstArguments (may be any combination):
1123995Spst  -sstring - digests string
1133995Spst  -t       - runs time trial
1143995Spst  -x       - runs test script
1153995Spst  filename - digests file
1163995Spst  (none)   - digests standard input
1173995Spst */
1186562Sphkint
11976988Srumain(int argc, char *argv[])
1203995Spst{
121176095Sobrien	int	ch;
1226562Sphk	char   *p;
123130351Seik	char	buf[HEX_DIGEST_LENGTH];
124176095Sobrien	int	failed;
125130351Seik 	unsigned	digest;
126130351Seik 	const char*	progname;
127176095Sobrien
128130351Seik 	if ((progname = strrchr(argv[0], '/')) == NULL)
129130351Seik 		progname = argv[0];
130130351Seik 	else
131130351Seik 		progname++;
132176095Sobrien
133130351Seik 	for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++)
134130351Seik 		if (strcasecmp(Algorithm[digest].progname, progname) == 0)
135130351Seik 			break;
136176095Sobrien
137130918Seik 	if (digest == sizeof(Algorithm)/sizeof(*Algorithm))
138130351Seik 		digest = 0;
1393995Spst
140121914Sse	failed = 0;
14178756Sru	while ((ch = getopt(argc, argv, "pqrs:tx")) != -1)
14276988Sru		switch (ch) {
14376988Sru		case 'p':
144130351Seik			MDFilter(&Algorithm[digest], 1);
14576988Sru			break;
14676988Sru		case 'q':
14776988Sru			qflag = 1;
14876988Sru			break;
14976988Sru		case 'r':
15076988Sru			rflag = 1;
15176988Sru			break;
15276988Sru		case 's':
15388226Sphk			sflag = 1;
154130351Seik			MDString(&Algorithm[digest], optarg);
15576988Sru			break;
15676988Sru		case 't':
157130351Seik			MDTimeTrial(&Algorithm[digest]);
15876988Sru			break;
15976988Sru		case 'x':
160130351Seik			MDTestSuite(&Algorithm[digest]);
16176988Sru			break;
16276988Sru		default:
163130351Seik			usage(&Algorithm[digest]);
16432074Ssteve		}
16576988Sru	argc -= optind;
16676988Sru	argv += optind;
16776988Sru
16876988Sru	if (*argv) {
16976988Sru		do {
170130351Seik			p = Algorithm[digest].File(*argv, buf);
171121914Sse			if (!p) {
17276988Sru				warn("%s", *argv);
173121914Sse				failed++;
174121914Sse			} else {
17554109Sobrien				if (qflag)
17654109Sobrien					printf("%s\n", p);
17754109Sobrien				else if (rflag)
17876988Sru					printf("%s %s\n", p, *argv);
17952949Sobrien				else
180176095Sobrien					printf("%s (%s) = %s\n",
181176095Sobrien					    Algorithm[digest].name, *argv, p);
182121914Sse			}
18376988Sru		} while (*++argv);
18488226Sphk	} else if (!sflag && (optind == 1 || qflag || rflag))
185130351Seik		MDFilter(&Algorithm[digest], 0);
1863995Spst
187121914Sse	if (failed != 0)
188121914Sse		return (1);
189176095Sobrien
1906562Sphk	return (0);
1913995Spst}
1926562Sphk/*
1936562Sphk * Digests a string and prints the result.
1943995Spst */
1956562Sphkstatic void
196130351SeikMDString(Algorithm_t *alg, const char *string)
1973995Spst{
19848953Sbillf	size_t len = strlen(string);
199130351Seik	char buf[HEX_DIGEST_LENGTH];
2003995Spst
20154109Sobrien	if (qflag)
202130351Seik		printf("%s\n", alg->Data(string, len, buf));
20354109Sobrien	else if (rflag)
204130351Seik		printf("%s \"%s\"\n", alg->Data(string, len, buf), string);
20552949Sobrien	else
206130351Seik		printf("%s (\"%s\") = %s\n", alg->name, string, alg->Data(string, len, buf));
2073995Spst}
2086562Sphk/*
2096562Sphk * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
2103995Spst */
2116562Sphkstatic void
212130351SeikMDTimeTrial(Algorithm_t *alg)
2133995Spst{
214130351Seik	DIGEST_CTX context;
215110840Ssilby	struct rusage before, after;
216110840Ssilby	struct timeval total;
217110840Ssilby	float seconds;
2186725Sphk	unsigned char block[TEST_BLOCK_LEN];
2196562Sphk	unsigned int i;
220176095Sobrien	char *p, buf[HEX_DIGEST_LENGTH];
2213995Spst
222176095Sobrien	printf("%s time trial. Digesting %d %d-byte blocks ...",
223130351Seik	    alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
22446226Skris	fflush(stdout);
2253995Spst
2266562Sphk	/* Initialize block */
2276562Sphk	for (i = 0; i < TEST_BLOCK_LEN; i++)
2286562Sphk		block[i] = (unsigned char) (i & 0xff);
2293995Spst
2306562Sphk	/* Start timer */
231110840Ssilby	getrusage(0, &before);
2323995Spst
2336562Sphk	/* Digest blocks */
234130351Seik	alg->Init(&context);
2356562Sphk	for (i = 0; i < TEST_BLOCK_COUNT; i++)
236130351Seik		alg->Update(&context, block, TEST_BLOCK_LEN);
237130351Seik	p = alg->End(&context, buf);
2383995Spst
2396562Sphk	/* Stop timer */
240110840Ssilby	getrusage(0, &after);
241110840Ssilby	timersub(&after.ru_utime, &before.ru_utime, &total);
242110840Ssilby	seconds = total.tv_sec + (float) total.tv_usec / 1000000;
2433995Spst
2446562Sphk	printf(" done\n");
2456562Sphk	printf("Digest = %s", p);
246110840Ssilby	printf("\nTime = %f seconds\n", seconds);
247176095Sobrien	printf("Speed = %f bytes/second\n",
248110840Ssilby	    (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds);
2493995Spst}
2506562Sphk/*
2516562Sphk * Digests a reference suite of strings and prints the results.
2523995Spst */
253109870Ssilby
254130351Seikconst char *MDTestInput[MDTESTCOUNT] = {
255176095Sobrien	"",
256109870Ssilby	"a",
257109870Ssilby	"abc",
258109870Ssilby	"message digest",
259109870Ssilby	"abcdefghijklmnopqrstuvwxyz",
260109870Ssilby	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
261109870Ssilby	"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
262130351Seik	"MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \
263130351Seikthat its security is in some doubt"
264109870Ssilby};
265109870Ssilby
266130351Seikconst char *MD5TestOutput[MDTESTCOUNT] = {
267109870Ssilby	"d41d8cd98f00b204e9800998ecf8427e",
268109870Ssilby	"0cc175b9c0f1b6a831c399e269772661",
269109870Ssilby	"900150983cd24fb0d6963f7d28e17f72",
270109870Ssilby	"f96b697d7cb7938d525a2f31aaf161d0",
271109870Ssilby	"c3fcd3d76192e4007dfb496cca67e13b",
272109870Ssilby	"d174ab98d277d9f5a5611c2c9f419d9f",
273109870Ssilby	"57edf4a22be3c955ac49da2e2107b67a",
274109870Ssilby	"b50663f41d44d92171cb9976bc118538"
275109870Ssilby};
276109870Ssilby
277130351Seikconst char *SHA1_TestOutput[MDTESTCOUNT] = {
278130351Seik	"da39a3ee5e6b4b0d3255bfef95601890afd80709",
279130351Seik	"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
280130351Seik	"a9993e364706816aba3e25717850c26c9cd0d89d",
281130351Seik	"c12252ceda8be8994d5fa0290a47231c1d16aae3",
282130351Seik	"32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
283130351Seik	"761c457bf73b14d27e9e9265c46f4b4dda11f940",
284130351Seik	"50abf5706a150990a08b2c5ea40fa0e585554732",
285130351Seik	"18eca4333979c4181199b7b4fab8786d16cf2846"
286130351Seik};
287130351Seik
288143334Scpercivaconst char *SHA256_TestOutput[MDTESTCOUNT] = {
289143334Scperciva	"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
290143334Scperciva	"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
291143334Scperciva	"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
292143334Scperciva	"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650",
293143334Scperciva	"71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73",
294143334Scperciva	"db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0",
295143334Scperciva	"f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e",
296143334Scperciva	"e6eae09f10ad4122a0e2a4075761d185a272ebd9f5aa489e998ff2f09cbfdd9f"
297143334Scperciva};
298143334Scperciva
299130351Seikconst char *RIPEMD160_TestOutput[MDTESTCOUNT] = {
300130351Seik	"9c1185a5c5e9fc54612808977ee8f548b2258d31",
301130351Seik	"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
302130351Seik	"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
303130351Seik	"5d0689ef49d2fae572b881b123a85ffa21595f36",
304130351Seik	"f71c27109c692c1b56bbdceb5b9d2865b3708dbc",
305130351Seik	"b0e20b6e3116640286ed3a87a5713079b21f5189",
306130351Seik	"9b752e45573d4b39f4dbd3323cab82bf63326bfb",
307130351Seik	"5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32"
308130351Seik};
309130351Seik
3106562Sphkstatic void
311130351SeikMDTestSuite(Algorithm_t *alg)
3123995Spst{
313109870Ssilby	int i;
314130351Seik	char buffer[HEX_DIGEST_LENGTH];
31532086Ssteve
316130351Seik	printf("%s test suite:\n", alg->name);
317130351Seik	for (i = 0; i < MDTESTCOUNT; i++) {
318130351Seik		(*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer);
319130351Seik		printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer);
320130351Seik		if (strcmp(buffer, (*alg->TestOutput)[i]) == 0)
321109870Ssilby			printf(" - verified correct\n");
322109870Ssilby		else
323109870Ssilby			printf(" - INCORRECT RESULT!\n");
324109870Ssilby	}
3253995Spst}
3263995Spst
3276562Sphk/*
3286562Sphk * Digests the standard input and prints the result.
3293995Spst */
3306562Sphkstatic void
331130351SeikMDFilter(Algorithm_t *alg, int tee)
3323995Spst{
333130351Seik	DIGEST_CTX context;
33476988Sru	unsigned int len;
33532074Ssteve	unsigned char buffer[BUFSIZ];
336130351Seik	char buf[HEX_DIGEST_LENGTH];
3373995Spst
338130351Seik	alg->Init(&context);
33932074Ssteve	while ((len = fread(buffer, 1, BUFSIZ, stdin))) {
34076988Sru		if (tee && len != fwrite(buffer, 1, len, stdout))
34137421Scharnier			err(1, "stdout");
342130351Seik		alg->Update(&context, buffer, len);
3436725Sphk	}
344130351Seik	printf("%s\n", alg->End(&context, buf));
3453995Spst}
34632074Ssteve
34732074Sstevestatic void
348130351Seikusage(Algorithm_t *alg)
34932074Ssteve{
35032086Ssteve
351130351Seik	fprintf(stderr, "usage: %s [-pqrtx] [-s string] [files ...]\n", alg->progname);
35232074Ssteve	exit(1);
35332074Ssteve}
354