md5.c revision 130351
1290001Sglebius/* 2290001Sglebius * Derived from: 3290001Sglebius * 4290001Sglebius * MDDRIVER.C - test driver for MD2, MD4 and MD5 5290001Sglebius */ 6290001Sglebius 7290001Sglebius/* 8290001Sglebius * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All 9290001Sglebius * rights reserved. 10290001Sglebius * 11290001Sglebius * RSA Data Security, Inc. makes no representations concerning either 12290001Sglebius * the merchantability of this software or the suitability of this 13290001Sglebius * software for any particular purpose. It is provided "as is" 14290001Sglebius * without express or implied warranty of any kind. 15290001Sglebius * 16290001Sglebius * These notices must be retained in any copies of any part of this 17290001Sglebius * documentation and/or software. 18290001Sglebius */ 19290001Sglebius 20290001Sglebius#include <sys/cdefs.h> 21290001Sglebius__FBSDID("$FreeBSD: head/sbin/md5/md5.c 130351 2004-06-11 16:07:02Z eik $"); 22290001Sglebius 23290001Sglebius#include <sys/types.h> 24290001Sglebius#include <sys/time.h> 25290001Sglebius#include <sys/resource.h> 26290001Sglebius#include <err.h> 27290001Sglebius#include <md5.h> 28290001Sglebius#include <ripemd.h> 29290001Sglebius#include <sha.h> 30290001Sglebius#include <stdio.h> 31290001Sglebius#include <stdlib.h> 32290001Sglebius#include <string.h> 33290001Sglebius#include <time.h> 34290001Sglebius#include <unistd.h> 35290001Sglebius 36290001Sglebius/* 37290001Sglebius * Length of test block, number of test blocks. 38290001Sglebius */ 39290001Sglebius#define TEST_BLOCK_LEN 10000 40290001Sglebius#define TEST_BLOCK_COUNT 100000 41290001Sglebius#define MDTESTCOUNT 8 42290001Sglebius 43290001Sglebiusint qflag; 44290001Sglebiusint rflag; 45290001Sglebiusint sflag; 46290001Sglebius 47290001Sglebiustypedef void (DIGEST_Init)(void *); 48290001Sglebiustypedef void (DIGEST_Update)(void *, const unsigned char *, size_t); 49290001Sglebiustypedef char *(DIGEST_End)(void *, char *); 50290001Sglebius 51290001Sglebiusextern const char *MD5TestOutput[MDTESTCOUNT]; 52290001Sglebiusextern const char *SHA1_TestOutput[MDTESTCOUNT]; 53290001Sglebiusextern const char *RIPEMD160_TestOutput[MDTESTCOUNT]; 54290001Sglebius 55290001Sglebiustypedef struct Algorithm_t { 56290001Sglebius const char *progname; 57290001Sglebius const char *name; 58290001Sglebius const char *(*TestOutput)[MDTESTCOUNT]; 59290001Sglebius DIGEST_Init *Init; 60290001Sglebius DIGEST_Update *Update; 61290001Sglebius DIGEST_End *End; 62290001Sglebius char *(*Data)(const unsigned char *, unsigned int, char *); 63290001Sglebius char *(*File)(const char *, char *); 64290001Sglebius} Algorithm_t; 65290001Sglebius 66290001Sglebiusstatic void MD5_Update(MD5_CTX *, const unsigned char *, size_t); 67290001Sglebiusstatic void MDString(Algorithm_t *, const char *); 68290001Sglebiusstatic void MDTimeTrial(Algorithm_t *); 69290001Sglebiusstatic void MDTestSuite(Algorithm_t *); 70290001Sglebiusstatic void MDFilter(Algorithm_t *, int); 71290001Sglebiusstatic void usage(Algorithm_t *); 72290001Sglebius 73290001Sglebiustypedef union { 74290001Sglebius MD5_CTX md5; 75290001Sglebius SHA1_CTX sha1; 76290001Sglebius RIPEMD160_CTX ripemd160; 77290001Sglebius} DIGEST_CTX; 78290001Sglebius 79290001Sglebius/* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */ 80290001Sglebius#define HEX_DIGEST_LENGTH 41 81290001Sglebius 82290001Sglebius/* algorithm function table */ 83290001Sglebius 84290001Sglebiusstruct Algorithm_t Algorithm[] = { 85290001Sglebius { "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init, 86290001Sglebius (DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End, 87290001Sglebius &MD5Data, &MD5File }, 88290001Sglebius { "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init, 89290001Sglebius (DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End, 90290001Sglebius &SHA1_Data, &SHA1_File }, 91290001Sglebius { "rmd160", "RMD160", &RIPEMD160_TestOutput, 92290001Sglebius (DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update, 93290001Sglebius (DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File } 94290001Sglebius}; 95290001Sglebius 96290001Sglebiusstatic void 97290001SglebiusMD5_Update(MD5_CTX *c, const unsigned char *data, size_t len) 98290001Sglebius{ 99290001Sglebius MD5Update(c, data, len); 100290001Sglebius} 101290001Sglebius 102290001Sglebius/* Main driver. 103290001Sglebius 104290001SglebiusArguments (may be any combination): 105290001Sglebius -sstring - digests string 106290001Sglebius -t - runs time trial 107290001Sglebius -x - runs test script 108290001Sglebius filename - digests file 109290001Sglebius (none) - digests standard input 110290001Sglebius */ 111290001Sglebiusint 112290001Sglebiusmain(int argc, char *argv[]) 113290001Sglebius{ 114290001Sglebius int ch; 115290001Sglebius char *p; 116290001Sglebius char buf[HEX_DIGEST_LENGTH]; 117290001Sglebius int failed; 118290001Sglebius unsigned digest; 119290001Sglebius const char* progname; 120290001Sglebius 121290001Sglebius if ((progname = strrchr(argv[0], '/')) == NULL) 122290001Sglebius progname = argv[0]; 123290001Sglebius else 124290001Sglebius progname++; 125290001Sglebius 126290001Sglebius for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++) 127290001Sglebius if (strcasecmp(Algorithm[digest].progname, progname) == 0) 128290001Sglebius break; 129290001Sglebius 130290001Sglebius if (Algorithm[digest].progname == NULL) 131290001Sglebius digest = 0; 132290001Sglebius 133290001Sglebius failed = 0; 134290001Sglebius while ((ch = getopt(argc, argv, "pqrs:tx")) != -1) 135290001Sglebius switch (ch) { 136290001Sglebius case 'p': 137290001Sglebius MDFilter(&Algorithm[digest], 1); 138290001Sglebius break; 139290001Sglebius case 'q': 140290001Sglebius qflag = 1; 141290001Sglebius break; 142290001Sglebius case 'r': 143290001Sglebius rflag = 1; 144290001Sglebius break; 145290001Sglebius case 's': 146290001Sglebius sflag = 1; 147290001Sglebius MDString(&Algorithm[digest], optarg); 148290001Sglebius break; 149290001Sglebius case 't': 150290001Sglebius MDTimeTrial(&Algorithm[digest]); 151290001Sglebius break; 152290001Sglebius case 'x': 153290001Sglebius MDTestSuite(&Algorithm[digest]); 154290001Sglebius break; 155290001Sglebius default: 156290001Sglebius usage(&Algorithm[digest]); 157290001Sglebius } 158290001Sglebius argc -= optind; 159290001Sglebius argv += optind; 160290001Sglebius 161290001Sglebius if (*argv) { 162290001Sglebius do { 163290001Sglebius p = Algorithm[digest].File(*argv, buf); 164290001Sglebius if (!p) { 165290001Sglebius warn("%s", *argv); 166290001Sglebius failed++; 167290001Sglebius } else { 168290001Sglebius if (qflag) 169290001Sglebius printf("%s\n", p); 170290001Sglebius else if (rflag) 171290001Sglebius printf("%s %s\n", p, *argv); 172290001Sglebius else 173290001Sglebius printf("%s (%s) = %s\n", Algorithm[digest].name, *argv, p); 174290001Sglebius } 175290001Sglebius } while (*++argv); 176290001Sglebius } else if (!sflag && (optind == 1 || qflag || rflag)) 177290001Sglebius MDFilter(&Algorithm[digest], 0); 178290001Sglebius 179290001Sglebius if (failed != 0) 180290001Sglebius return (1); 181290001Sglebius 182290001Sglebius return (0); 183290001Sglebius} 184290001Sglebius/* 185290001Sglebius * Digests a string and prints the result. 186290001Sglebius */ 187290001Sglebiusstatic void 188290001SglebiusMDString(Algorithm_t *alg, const char *string) 189290001Sglebius{ 190290001Sglebius size_t len = strlen(string); 191290001Sglebius char buf[HEX_DIGEST_LENGTH]; 192290001Sglebius 193290001Sglebius if (qflag) 194290001Sglebius printf("%s\n", alg->Data(string, len, buf)); 195290001Sglebius else if (rflag) 196290001Sglebius printf("%s \"%s\"\n", alg->Data(string, len, buf), string); 197290001Sglebius else 198290001Sglebius printf("%s (\"%s\") = %s\n", alg->name, string, alg->Data(string, len, buf)); 199290001Sglebius} 200290001Sglebius/* 201290001Sglebius * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. 202290001Sglebius */ 203290001Sglebiusstatic void 204290001SglebiusMDTimeTrial(Algorithm_t *alg) 205290001Sglebius{ 206290001Sglebius DIGEST_CTX context; 207290001Sglebius struct rusage before, after; 208290001Sglebius struct timeval total; 209290001Sglebius float seconds; 210290001Sglebius unsigned char block[TEST_BLOCK_LEN]; 211290001Sglebius unsigned int i; 212290001Sglebius char *p, buf[HEX_DIGEST_LENGTH]; 213290001Sglebius 214290001Sglebius printf 215290001Sglebius ("%s time trial. Digesting %d %d-byte blocks ...", 216290001Sglebius alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN); 217290001Sglebius fflush(stdout); 218290001Sglebius 219290001Sglebius /* Initialize block */ 220290001Sglebius for (i = 0; i < TEST_BLOCK_LEN; i++) 221290001Sglebius block[i] = (unsigned char) (i & 0xff); 222290001Sglebius 223290001Sglebius /* Start timer */ 224290001Sglebius getrusage(0, &before); 225290001Sglebius 226290001Sglebius /* Digest blocks */ 227290001Sglebius alg->Init(&context); 228290001Sglebius for (i = 0; i < TEST_BLOCK_COUNT; i++) 229290001Sglebius alg->Update(&context, block, TEST_BLOCK_LEN); 230290001Sglebius p = alg->End(&context, buf); 231290001Sglebius 232290001Sglebius /* Stop timer */ 233290001Sglebius getrusage(0, &after); 234290001Sglebius timersub(&after.ru_utime, &before.ru_utime, &total); 235290001Sglebius seconds = total.tv_sec + (float) total.tv_usec / 1000000; 236290001Sglebius 237290001Sglebius printf(" done\n"); 238290001Sglebius printf("Digest = %s", p); 239290001Sglebius printf("\nTime = %f seconds\n", seconds); 240290001Sglebius printf 241290001Sglebius ("Speed = %f bytes/second\n", 242290001Sglebius (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds); 243290001Sglebius} 244290001Sglebius/* 245290001Sglebius * Digests a reference suite of strings and prints the results. 246290001Sglebius */ 247290001Sglebius 248290001Sglebiusconst char *MDTestInput[MDTESTCOUNT] = { 249290001Sglebius "", 250290001Sglebius "a", 251290001Sglebius "abc", 252290001Sglebius "message digest", 253290001Sglebius "abcdefghijklmnopqrstuvwxyz", 254290001Sglebius "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 255290001Sglebius "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 256290001Sglebius "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \ 257290001Sglebiusthat its security is in some doubt" 258290001Sglebius}; 259290001Sglebius 260290001Sglebiusconst char *MD5TestOutput[MDTESTCOUNT] = { 261290001Sglebius "d41d8cd98f00b204e9800998ecf8427e", 262290001Sglebius "0cc175b9c0f1b6a831c399e269772661", 263290001Sglebius "900150983cd24fb0d6963f7d28e17f72", 264290001Sglebius "f96b697d7cb7938d525a2f31aaf161d0", 265290001Sglebius "c3fcd3d76192e4007dfb496cca67e13b", 266 "d174ab98d277d9f5a5611c2c9f419d9f", 267 "57edf4a22be3c955ac49da2e2107b67a", 268 "b50663f41d44d92171cb9976bc118538" 269}; 270 271const char *SHA1_TestOutput[MDTESTCOUNT] = { 272 "da39a3ee5e6b4b0d3255bfef95601890afd80709", 273 "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", 274 "a9993e364706816aba3e25717850c26c9cd0d89d", 275 "c12252ceda8be8994d5fa0290a47231c1d16aae3", 276 "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", 277 "761c457bf73b14d27e9e9265c46f4b4dda11f940", 278 "50abf5706a150990a08b2c5ea40fa0e585554732", 279 "18eca4333979c4181199b7b4fab8786d16cf2846" 280}; 281 282const char *RIPEMD160_TestOutput[MDTESTCOUNT] = { 283 "9c1185a5c5e9fc54612808977ee8f548b2258d31", 284 "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", 285 "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", 286 "5d0689ef49d2fae572b881b123a85ffa21595f36", 287 "f71c27109c692c1b56bbdceb5b9d2865b3708dbc", 288 "b0e20b6e3116640286ed3a87a5713079b21f5189", 289 "9b752e45573d4b39f4dbd3323cab82bf63326bfb", 290 "5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32" 291}; 292 293static void 294MDTestSuite(Algorithm_t *alg) 295{ 296 int i; 297 char buffer[HEX_DIGEST_LENGTH]; 298 299 printf("%s test suite:\n", alg->name); 300 for (i = 0; i < MDTESTCOUNT; i++) { 301 (*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer); 302 printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer); 303 if (strcmp(buffer, (*alg->TestOutput)[i]) == 0) 304 printf(" - verified correct\n"); 305 else 306 printf(" - INCORRECT RESULT!\n"); 307 } 308} 309 310/* 311 * Digests the standard input and prints the result. 312 */ 313static void 314MDFilter(Algorithm_t *alg, int tee) 315{ 316 DIGEST_CTX context; 317 unsigned int len; 318 unsigned char buffer[BUFSIZ]; 319 char buf[HEX_DIGEST_LENGTH]; 320 321 alg->Init(&context); 322 while ((len = fread(buffer, 1, BUFSIZ, stdin))) { 323 if (tee && len != fwrite(buffer, 1, len, stdout)) 324 err(1, "stdout"); 325 alg->Update(&context, buffer, len); 326 } 327 printf("%s\n", alg->End(&context, buf)); 328} 329 330static void 331usage(Algorithm_t *alg) 332{ 333 334 fprintf(stderr, "usage: %s [-pqrtx] [-s string] [files ...]\n", alg->progname); 335 exit(1); 336} 337