19b1fd0e5SPoul-Henning Kamp /* 29b1fd0e5SPoul-Henning Kamp * Derived from: 323b5892fSPhilippe Charnier * 49b1fd0e5SPoul-Henning Kamp * MDDRIVER.C - test driver for MD2, MD4 and MD5 5e1645093SPaul Traina */ 6e1645093SPaul Traina 79b1fd0e5SPoul-Henning Kamp /* 89b1fd0e5SPoul-Henning Kamp * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All 99b1fd0e5SPoul-Henning Kamp * rights reserved. 109b1fd0e5SPoul-Henning Kamp * 119b1fd0e5SPoul-Henning Kamp * RSA Data Security, Inc. makes no representations concerning either 129b1fd0e5SPoul-Henning Kamp * the merchantability of this software or the suitability of this 139b1fd0e5SPoul-Henning Kamp * software for any particular purpose. It is provided "as is" 149b1fd0e5SPoul-Henning Kamp * without express or implied warranty of any kind. 159b1fd0e5SPoul-Henning Kamp * 169b1fd0e5SPoul-Henning Kamp * These notices must be retained in any copies of any part of this 179b1fd0e5SPoul-Henning Kamp * documentation and/or software. 18e1645093SPaul Traina */ 19e1645093SPaul Traina 20c69284caSDavid E. O'Brien #include <sys/cdefs.h> 21c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$"); 22e1645093SPaul Traina 2323b5892fSPhilippe Charnier #include <sys/types.h> 24ed4edda0SMike Silbersack #include <sys/time.h> 25ed4edda0SMike Silbersack #include <sys/resource.h> 2623b5892fSPhilippe Charnier #include <err.h> 2723b5892fSPhilippe Charnier #include <md5.h> 28cb49d42bSOliver Eikemeier #include <ripemd.h> 29cb49d42bSOliver Eikemeier #include <sha.h> 30186c183cSColin Percival #include <sha256.h> 311ab6205cSBruce Evans #include <stdio.h> 32cafefe8cSDima Dorfman #include <stdlib.h> 33b76bf6fcSBill Fumerola #include <string.h> 3440dbfd1aSDag-Erling Smørgrav #include <time.h> 3540dbfd1aSDag-Erling Smørgrav #include <unistd.h> 361ab6205cSBruce Evans 379b1fd0e5SPoul-Henning Kamp /* 389b1fd0e5SPoul-Henning Kamp * Length of test block, number of test blocks. 39e1645093SPaul Traina */ 4093606d6eSKris Kennaway #define TEST_BLOCK_LEN 10000 4193606d6eSKris Kennaway #define TEST_BLOCK_COUNT 100000 42cb49d42bSOliver Eikemeier #define MDTESTCOUNT 8 43e1645093SPaul Traina 442963da13SDavid E. O'Brien int qflag; 459e18a3bdSDavid E. O'Brien int rflag; 46dc015e16SPoul-Henning Kamp int sflag; 479e18a3bdSDavid E. O'Brien 48cb49d42bSOliver Eikemeier typedef void (DIGEST_Init)(void *); 49cb49d42bSOliver Eikemeier typedef void (DIGEST_Update)(void *, const unsigned char *, size_t); 50cb49d42bSOliver Eikemeier typedef char *(DIGEST_End)(void *, char *); 51cb49d42bSOliver Eikemeier 52cb49d42bSOliver Eikemeier extern const char *MD5TestOutput[MDTESTCOUNT]; 53cb49d42bSOliver Eikemeier extern const char *SHA1_TestOutput[MDTESTCOUNT]; 54186c183cSColin Percival extern const char *SHA256_TestOutput[MDTESTCOUNT]; 55cb49d42bSOliver Eikemeier extern const char *RIPEMD160_TestOutput[MDTESTCOUNT]; 56cb49d42bSOliver Eikemeier 57cb49d42bSOliver Eikemeier typedef struct Algorithm_t { 58cb49d42bSOliver Eikemeier const char *progname; 59cb49d42bSOliver Eikemeier const char *name; 60cb49d42bSOliver Eikemeier const char *(*TestOutput)[MDTESTCOUNT]; 61cb49d42bSOliver Eikemeier DIGEST_Init *Init; 62cb49d42bSOliver Eikemeier DIGEST_Update *Update; 63cb49d42bSOliver Eikemeier DIGEST_End *End; 6425a14196SPoul-Henning Kamp char *(*Data)(const void *, unsigned int, char *); 65cb49d42bSOliver Eikemeier char *(*File)(const char *, char *); 66cb49d42bSOliver Eikemeier } Algorithm_t; 67cb49d42bSOliver Eikemeier 68cb49d42bSOliver Eikemeier static void MD5_Update(MD5_CTX *, const unsigned char *, size_t); 69cb49d42bSOliver Eikemeier static void MDString(Algorithm_t *, const char *); 70cb49d42bSOliver Eikemeier static void MDTimeTrial(Algorithm_t *); 71cb49d42bSOliver Eikemeier static void MDTestSuite(Algorithm_t *); 72cb49d42bSOliver Eikemeier static void MDFilter(Algorithm_t *, int); 73cb49d42bSOliver Eikemeier static void usage(Algorithm_t *); 74cb49d42bSOliver Eikemeier 75cb49d42bSOliver Eikemeier typedef union { 76cb49d42bSOliver Eikemeier MD5_CTX md5; 77cb49d42bSOliver Eikemeier SHA1_CTX sha1; 78186c183cSColin Percival SHA256_CTX sha256; 79cb49d42bSOliver Eikemeier RIPEMD160_CTX ripemd160; 80cb49d42bSOliver Eikemeier } DIGEST_CTX; 81cb49d42bSOliver Eikemeier 82186c183cSColin Percival /* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH, 83186c183cSColin Percival SHA256_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */ 84186c183cSColin Percival #define HEX_DIGEST_LENGTH 65 85cb49d42bSOliver Eikemeier 86cb49d42bSOliver Eikemeier /* algorithm function table */ 87cb49d42bSOliver Eikemeier 88cb49d42bSOliver Eikemeier struct Algorithm_t Algorithm[] = { 89cb49d42bSOliver Eikemeier { "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init, 90cb49d42bSOliver Eikemeier (DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End, 91cb49d42bSOliver Eikemeier &MD5Data, &MD5File }, 92cb49d42bSOliver Eikemeier { "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init, 93cb49d42bSOliver Eikemeier (DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End, 94cb49d42bSOliver Eikemeier &SHA1_Data, &SHA1_File }, 95186c183cSColin Percival { "sha256", "SHA256", &SHA256_TestOutput, (DIGEST_Init*)&SHA256_Init, 96186c183cSColin Percival (DIGEST_Update*)&SHA256_Update, (DIGEST_End*)&SHA256_End, 97186c183cSColin Percival &SHA256_Data, &SHA256_File }, 98cb49d42bSOliver Eikemeier { "rmd160", "RMD160", &RIPEMD160_TestOutput, 99cb49d42bSOliver Eikemeier (DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update, 100cb49d42bSOliver Eikemeier (DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File } 101cb49d42bSOliver Eikemeier }; 102cb49d42bSOliver Eikemeier 103cb49d42bSOliver Eikemeier static void 104cb49d42bSOliver Eikemeier MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len) 105cb49d42bSOliver Eikemeier { 106cb49d42bSOliver Eikemeier MD5Update(c, data, len); 107cb49d42bSOliver Eikemeier } 108e1645093SPaul Traina 109e1645093SPaul Traina /* Main driver. 110e1645093SPaul Traina 111e1645093SPaul Traina Arguments (may be any combination): 112e1645093SPaul Traina -sstring - digests string 113e1645093SPaul Traina -t - runs time trial 114e1645093SPaul Traina -x - runs test script 115e1645093SPaul Traina filename - digests file 116e1645093SPaul Traina (none) - digests standard input 117e1645093SPaul Traina */ 1189b1fd0e5SPoul-Henning Kamp int 11905fe5d56SRuslan Ermilov main(int argc, char *argv[]) 120e1645093SPaul Traina { 1219a9791afSSteve Price int ch; 1229b1fd0e5SPoul-Henning Kamp char *p; 123cb49d42bSOliver Eikemeier char buf[HEX_DIGEST_LENGTH]; 1245758d949SStefan Eßer int failed; 125cb49d42bSOliver Eikemeier unsigned digest; 126cb49d42bSOliver Eikemeier const char* progname; 127cb49d42bSOliver Eikemeier 128cb49d42bSOliver Eikemeier if ((progname = strrchr(argv[0], '/')) == NULL) 129cb49d42bSOliver Eikemeier progname = argv[0]; 130cb49d42bSOliver Eikemeier else 131cb49d42bSOliver Eikemeier progname++; 132cb49d42bSOliver Eikemeier 133cb49d42bSOliver Eikemeier for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++) 134cb49d42bSOliver Eikemeier if (strcasecmp(Algorithm[digest].progname, progname) == 0) 135cb49d42bSOliver Eikemeier break; 136cb49d42bSOliver Eikemeier 1377b89c134SOliver Eikemeier if (digest == sizeof(Algorithm)/sizeof(*Algorithm)) 138cb49d42bSOliver Eikemeier digest = 0; 139e1645093SPaul Traina 1405758d949SStefan Eßer failed = 0; 141085d2345SRuslan Ermilov while ((ch = getopt(argc, argv, "pqrs:tx")) != -1) 1429a9791afSSteve Price switch (ch) { 143716847a6SSteve Price case 'p': 144cb49d42bSOliver Eikemeier MDFilter(&Algorithm[digest], 1); 145716847a6SSteve Price break; 1462963da13SDavid E. O'Brien case 'q': 1472963da13SDavid E. O'Brien qflag = 1; 1482963da13SDavid E. O'Brien break; 1499e18a3bdSDavid E. O'Brien case 'r': 1509e18a3bdSDavid E. O'Brien rflag = 1; 1519e18a3bdSDavid E. O'Brien break; 152716847a6SSteve Price case 's': 153dc015e16SPoul-Henning Kamp sflag = 1; 154cb49d42bSOliver Eikemeier MDString(&Algorithm[digest], optarg); 155716847a6SSteve Price break; 156716847a6SSteve Price case 't': 157cb49d42bSOliver Eikemeier MDTimeTrial(&Algorithm[digest]); 158716847a6SSteve Price break; 159716847a6SSteve Price case 'x': 160cb49d42bSOliver Eikemeier MDTestSuite(&Algorithm[digest]); 161716847a6SSteve Price break; 162716847a6SSteve Price default: 163cb49d42bSOliver Eikemeier usage(&Algorithm[digest]); 1649b1fd0e5SPoul-Henning Kamp } 16505fe5d56SRuslan Ermilov argc -= optind; 16605fe5d56SRuslan Ermilov argv += optind; 16705fe5d56SRuslan Ermilov 16805fe5d56SRuslan Ermilov if (*argv) { 16905fe5d56SRuslan Ermilov do { 170cb49d42bSOliver Eikemeier p = Algorithm[digest].File(*argv, buf); 1715758d949SStefan Eßer if (!p) { 17205fe5d56SRuslan Ermilov warn("%s", *argv); 1735758d949SStefan Eßer failed++; 1745758d949SStefan Eßer } else { 1752963da13SDavid E. O'Brien if (qflag) 1762963da13SDavid E. O'Brien printf("%s\n", p); 1772963da13SDavid E. O'Brien else if (rflag) 17805fe5d56SRuslan Ermilov printf("%s %s\n", p, *argv); 1799e18a3bdSDavid E. O'Brien else 1809c6c6249SDavid E. O'Brien printf("%s (%s) = %s\n", 1819c6c6249SDavid E. O'Brien Algorithm[digest].name, *argv, p); 1825758d949SStefan Eßer } 18305fe5d56SRuslan Ermilov } while (*++argv); 184dc015e16SPoul-Henning Kamp } else if (!sflag && (optind == 1 || qflag || rflag)) 185cb49d42bSOliver Eikemeier MDFilter(&Algorithm[digest], 0); 186e1645093SPaul Traina 1875758d949SStefan Eßer if (failed != 0) 1885758d949SStefan Eßer return (1); 1895758d949SStefan Eßer 190e1645093SPaul Traina return (0); 191e1645093SPaul Traina } 1929b1fd0e5SPoul-Henning Kamp /* 1939b1fd0e5SPoul-Henning Kamp * Digests a string and prints the result. 194e1645093SPaul Traina */ 1959b1fd0e5SPoul-Henning Kamp static void 196cb49d42bSOliver Eikemeier MDString(Algorithm_t *alg, const char *string) 197e1645093SPaul Traina { 198b76bf6fcSBill Fumerola size_t len = strlen(string); 199cb49d42bSOliver Eikemeier char buf[HEX_DIGEST_LENGTH]; 200e1645093SPaul Traina 2012963da13SDavid E. O'Brien if (qflag) 202cb49d42bSOliver Eikemeier printf("%s\n", alg->Data(string, len, buf)); 2032963da13SDavid E. O'Brien else if (rflag) 204cb49d42bSOliver Eikemeier printf("%s \"%s\"\n", alg->Data(string, len, buf), string); 2059e18a3bdSDavid E. O'Brien else 206cb49d42bSOliver Eikemeier printf("%s (\"%s\") = %s\n", alg->name, string, alg->Data(string, len, buf)); 207e1645093SPaul Traina } 2089b1fd0e5SPoul-Henning Kamp /* 2099b1fd0e5SPoul-Henning Kamp * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. 210e1645093SPaul Traina */ 2119b1fd0e5SPoul-Henning Kamp static void 212cb49d42bSOliver Eikemeier MDTimeTrial(Algorithm_t *alg) 213e1645093SPaul Traina { 214cb49d42bSOliver Eikemeier DIGEST_CTX context; 215ed4edda0SMike Silbersack struct rusage before, after; 216ed4edda0SMike Silbersack struct timeval total; 217ed4edda0SMike Silbersack float seconds; 21823b406e1SPoul-Henning Kamp unsigned char block[TEST_BLOCK_LEN]; 219e1645093SPaul Traina unsigned int i; 220cb49d42bSOliver Eikemeier char *p, buf[HEX_DIGEST_LENGTH]; 221e1645093SPaul Traina 2229c6c6249SDavid E. O'Brien printf("%s time trial. Digesting %d %d-byte blocks ...", 223cb49d42bSOliver Eikemeier alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN); 22493606d6eSKris Kennaway fflush(stdout); 225e1645093SPaul Traina 226e1645093SPaul Traina /* Initialize block */ 227e1645093SPaul Traina for (i = 0; i < TEST_BLOCK_LEN; i++) 228e1645093SPaul Traina block[i] = (unsigned char) (i & 0xff); 229e1645093SPaul Traina 230e1645093SPaul Traina /* Start timer */ 2311f0e597dSKevin Lo getrusage(RUSAGE_SELF, &before); 232e1645093SPaul Traina 233e1645093SPaul Traina /* Digest blocks */ 234cb49d42bSOliver Eikemeier alg->Init(&context); 235e1645093SPaul Traina for (i = 0; i < TEST_BLOCK_COUNT; i++) 236cb49d42bSOliver Eikemeier alg->Update(&context, block, TEST_BLOCK_LEN); 237cb49d42bSOliver Eikemeier p = alg->End(&context, buf); 238e1645093SPaul Traina 239e1645093SPaul Traina /* Stop timer */ 2401f0e597dSKevin Lo getrusage(RUSAGE_SELF, &after); 241ed4edda0SMike Silbersack timersub(&after.ru_utime, &before.ru_utime, &total); 242ed4edda0SMike Silbersack seconds = total.tv_sec + (float) total.tv_usec / 1000000; 243e1645093SPaul Traina 244e1645093SPaul Traina printf(" done\n"); 2459b1fd0e5SPoul-Henning Kamp printf("Digest = %s", p); 246ed4edda0SMike Silbersack printf("\nTime = %f seconds\n", seconds); 2479c6c6249SDavid E. O'Brien printf("Speed = %f bytes/second\n", 248ed4edda0SMike Silbersack (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds); 249e1645093SPaul Traina } 2509b1fd0e5SPoul-Henning Kamp /* 2519b1fd0e5SPoul-Henning Kamp * Digests a reference suite of strings and prints the results. 252e1645093SPaul Traina */ 253bbe70882SMike Silbersack 254cb49d42bSOliver Eikemeier const char *MDTestInput[MDTESTCOUNT] = { 255bbe70882SMike Silbersack "", 256bbe70882SMike Silbersack "a", 257bbe70882SMike Silbersack "abc", 258bbe70882SMike Silbersack "message digest", 259bbe70882SMike Silbersack "abcdefghijklmnopqrstuvwxyz", 260bbe70882SMike Silbersack "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 261bbe70882SMike Silbersack "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 262cb49d42bSOliver Eikemeier "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \ 263cb49d42bSOliver Eikemeier that its security is in some doubt" 264bbe70882SMike Silbersack }; 265bbe70882SMike Silbersack 266cb49d42bSOliver Eikemeier const char *MD5TestOutput[MDTESTCOUNT] = { 267bbe70882SMike Silbersack "d41d8cd98f00b204e9800998ecf8427e", 268bbe70882SMike Silbersack "0cc175b9c0f1b6a831c399e269772661", 269bbe70882SMike Silbersack "900150983cd24fb0d6963f7d28e17f72", 270bbe70882SMike Silbersack "f96b697d7cb7938d525a2f31aaf161d0", 271bbe70882SMike Silbersack "c3fcd3d76192e4007dfb496cca67e13b", 272bbe70882SMike Silbersack "d174ab98d277d9f5a5611c2c9f419d9f", 273bbe70882SMike Silbersack "57edf4a22be3c955ac49da2e2107b67a", 274bbe70882SMike Silbersack "b50663f41d44d92171cb9976bc118538" 275bbe70882SMike Silbersack }; 276bbe70882SMike Silbersack 277cb49d42bSOliver Eikemeier const char *SHA1_TestOutput[MDTESTCOUNT] = { 278cb49d42bSOliver Eikemeier "da39a3ee5e6b4b0d3255bfef95601890afd80709", 279cb49d42bSOliver Eikemeier "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", 280cb49d42bSOliver Eikemeier "a9993e364706816aba3e25717850c26c9cd0d89d", 281cb49d42bSOliver Eikemeier "c12252ceda8be8994d5fa0290a47231c1d16aae3", 282cb49d42bSOliver Eikemeier "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", 283cb49d42bSOliver Eikemeier "761c457bf73b14d27e9e9265c46f4b4dda11f940", 284cb49d42bSOliver Eikemeier "50abf5706a150990a08b2c5ea40fa0e585554732", 285cb49d42bSOliver Eikemeier "18eca4333979c4181199b7b4fab8786d16cf2846" 286cb49d42bSOliver Eikemeier }; 287cb49d42bSOliver Eikemeier 288186c183cSColin Percival const char *SHA256_TestOutput[MDTESTCOUNT] = { 289186c183cSColin Percival "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 290186c183cSColin Percival "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", 291186c183cSColin Percival "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", 292186c183cSColin Percival "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650", 293186c183cSColin Percival "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73", 294186c183cSColin Percival "db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0", 295186c183cSColin Percival "f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e", 296186c183cSColin Percival "e6eae09f10ad4122a0e2a4075761d185a272ebd9f5aa489e998ff2f09cbfdd9f" 297186c183cSColin Percival }; 298186c183cSColin Percival 299cb49d42bSOliver Eikemeier const char *RIPEMD160_TestOutput[MDTESTCOUNT] = { 300cb49d42bSOliver Eikemeier "9c1185a5c5e9fc54612808977ee8f548b2258d31", 301cb49d42bSOliver Eikemeier "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", 302cb49d42bSOliver Eikemeier "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", 303cb49d42bSOliver Eikemeier "5d0689ef49d2fae572b881b123a85ffa21595f36", 304cb49d42bSOliver Eikemeier "f71c27109c692c1b56bbdceb5b9d2865b3708dbc", 305cb49d42bSOliver Eikemeier "b0e20b6e3116640286ed3a87a5713079b21f5189", 306cb49d42bSOliver Eikemeier "9b752e45573d4b39f4dbd3323cab82bf63326bfb", 307cb49d42bSOliver Eikemeier "5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32" 308cb49d42bSOliver Eikemeier }; 309cb49d42bSOliver Eikemeier 3109b1fd0e5SPoul-Henning Kamp static void 311cb49d42bSOliver Eikemeier MDTestSuite(Algorithm_t *alg) 312e1645093SPaul Traina { 313bbe70882SMike Silbersack int i; 314cb49d42bSOliver Eikemeier char buffer[HEX_DIGEST_LENGTH]; 3159a9791afSSteve Price 316cb49d42bSOliver Eikemeier printf("%s test suite:\n", alg->name); 317cb49d42bSOliver Eikemeier for (i = 0; i < MDTESTCOUNT; i++) { 318cb49d42bSOliver Eikemeier (*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer); 319cb49d42bSOliver Eikemeier printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer); 320cb49d42bSOliver Eikemeier if (strcmp(buffer, (*alg->TestOutput)[i]) == 0) 321bbe70882SMike Silbersack printf(" - verified correct\n"); 322bbe70882SMike Silbersack else 323bbe70882SMike Silbersack printf(" - INCORRECT RESULT!\n"); 324bbe70882SMike Silbersack } 325e1645093SPaul Traina } 326e1645093SPaul Traina 3279b1fd0e5SPoul-Henning Kamp /* 3289b1fd0e5SPoul-Henning Kamp * Digests the standard input and prints the result. 329e1645093SPaul Traina */ 3309b1fd0e5SPoul-Henning Kamp static void 331cb49d42bSOliver Eikemeier MDFilter(Algorithm_t *alg, int tee) 332e1645093SPaul Traina { 333cb49d42bSOliver Eikemeier DIGEST_CTX context; 33405fe5d56SRuslan Ermilov unsigned int len; 335716847a6SSteve Price unsigned char buffer[BUFSIZ]; 336cb49d42bSOliver Eikemeier char buf[HEX_DIGEST_LENGTH]; 337e1645093SPaul Traina 338cb49d42bSOliver Eikemeier alg->Init(&context); 339716847a6SSteve Price while ((len = fread(buffer, 1, BUFSIZ, stdin))) { 34005fe5d56SRuslan Ermilov if (tee && len != fwrite(buffer, 1, len, stdout)) 34123b5892fSPhilippe Charnier err(1, "stdout"); 342cb49d42bSOliver Eikemeier alg->Update(&context, buffer, len); 34323b406e1SPoul-Henning Kamp } 344cb49d42bSOliver Eikemeier printf("%s\n", alg->End(&context, buf)); 345e1645093SPaul Traina } 346716847a6SSteve Price 347716847a6SSteve Price static void 348cb49d42bSOliver Eikemeier usage(Algorithm_t *alg) 349716847a6SSteve Price { 3509a9791afSSteve Price 351cb49d42bSOliver Eikemeier fprintf(stderr, "usage: %s [-pqrtx] [-s string] [files ...]\n", alg->progname); 352716847a6SSteve Price exit(1); 353716847a6SSteve Price } 354