1 /* 2 * Derived from: 3 * 4 * MDDRIVER.C - test driver for MD2, MD4 and MD5 5 * 6 * $FreeBSD: src/sbin/md5/md5.c,v 1.33 2004/06/22 09:18:50 eik Exp $ 7 * $DragonFly: src/sbin/md5/md5.c,v 1.3 2005/03/09 16:18:55 corecode Exp $ 8 */ 9 10 /* 11 * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All 12 * rights reserved. 13 * 14 * RSA Data Security, Inc. makes no representations concerning either 15 * the merchantability of this software or the suitability of this 16 * software for any particular purpose. It is provided "as is" 17 * without express or implied warranty of any kind. 18 * 19 * These notices must be retained in any copies of any part of this 20 * documentation and/or software. 21 */ 22 23 #include <sys/cdefs.h> 24 25 #include <sys/types.h> 26 #include <sys/time.h> 27 #include <sys/resource.h> 28 #include <err.h> 29 #include <md5.h> 30 #include <ripemd.h> 31 #include <sha.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include <unistd.h> 37 38 /* 39 * Length of test block, number of test blocks. 40 */ 41 #define TEST_BLOCK_LEN 10000 42 #define TEST_BLOCK_COUNT 100000 43 #define MDTESTCOUNT 8 44 45 int qflag; 46 int rflag; 47 int sflag; 48 49 typedef void (DIGEST_Init)(void *); 50 typedef void (DIGEST_Update)(void *, const unsigned char *, size_t); 51 typedef char *(DIGEST_End)(void *, char *); 52 53 extern const char *MD5TestOutput[MDTESTCOUNT]; 54 extern const char *SHA1_TestOutput[MDTESTCOUNT]; 55 extern const char *RIPEMD160_TestOutput[MDTESTCOUNT]; 56 57 typedef struct Algorithm_t { 58 const char *progname; 59 const char *name; 60 const char *(*TestOutput)[MDTESTCOUNT]; 61 DIGEST_Init *Init; 62 DIGEST_Update *Update; 63 DIGEST_End *End; 64 char *(*Data)(const unsigned char *, unsigned int, char *); 65 char *(*File)(const char *, char *); 66 } Algorithm_t; 67 68 static void MD5_Update(MD5_CTX *, const unsigned char *, size_t); 69 static void MDString(Algorithm_t *, const char *); 70 static void MDTimeTrial(Algorithm_t *); 71 static void MDTestSuite(Algorithm_t *); 72 static void MDFilter(Algorithm_t *, int); 73 static void usage(Algorithm_t *); 74 75 typedef union { 76 MD5_CTX md5; 77 SHA1_CTX sha1; 78 RIPEMD160_CTX ripemd160; 79 } DIGEST_CTX; 80 81 /* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */ 82 #define HEX_DIGEST_LENGTH 41 83 84 /* algorithm function table */ 85 86 struct Algorithm_t Algorithm[] = { 87 { "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init, 88 (DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End, 89 &MD5Data, &MD5File }, 90 { "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init, 91 (DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End, 92 &SHA1_Data, &SHA1_File }, 93 { "rmd160", "RMD160", &RIPEMD160_TestOutput, 94 (DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update, 95 (DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File } 96 }; 97 98 static void 99 MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len) 100 { 101 MD5Update(c, data, len); 102 } 103 104 /* Main driver. 105 106 Arguments (may be any combination): 107 -sstring - digests string 108 -t - runs time trial 109 -x - runs test script 110 filename - digests file 111 (none) - digests standard input 112 */ 113 int 114 main(int argc, char *argv[]) 115 { 116 int ch; 117 char *p; 118 char buf[HEX_DIGEST_LENGTH]; 119 int failed; 120 unsigned digest; 121 const char* progname; 122 123 if ((progname = strrchr(argv[0], '/')) == NULL) 124 progname = argv[0]; 125 else 126 progname++; 127 128 for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++) 129 if (strcasecmp(Algorithm[digest].progname, progname) == 0) 130 break; 131 132 if (digest == sizeof(Algorithm)/sizeof(*Algorithm)) 133 digest = 0; 134 135 failed = 0; 136 while ((ch = getopt(argc, argv, "pqrs:tx")) != -1) 137 switch (ch) { 138 case 'p': 139 MDFilter(&Algorithm[digest], 1); 140 break; 141 case 'q': 142 qflag = 1; 143 break; 144 case 'r': 145 rflag = 1; 146 break; 147 case 's': 148 sflag = 1; 149 MDString(&Algorithm[digest], optarg); 150 break; 151 case 't': 152 MDTimeTrial(&Algorithm[digest]); 153 break; 154 case 'x': 155 MDTestSuite(&Algorithm[digest]); 156 break; 157 default: 158 usage(&Algorithm[digest]); 159 } 160 argc -= optind; 161 argv += optind; 162 163 if (*argv) { 164 do { 165 p = Algorithm[digest].File(*argv, buf); 166 if (!p) { 167 warn("%s", *argv); 168 failed++; 169 } else { 170 if (qflag) 171 printf("%s\n", p); 172 else if (rflag) 173 printf("%s %s\n", p, *argv); 174 else 175 printf("%s (%s) = %s\n", Algorithm[digest].name, *argv, p); 176 } 177 } while (*++argv); 178 } else if (!sflag && (optind == 1 || qflag || rflag)) 179 MDFilter(&Algorithm[digest], 0); 180 181 if (failed != 0) 182 return (1); 183 184 return (0); 185 } 186 /* 187 * Digests a string and prints the result. 188 */ 189 static void 190 MDString(Algorithm_t *alg, const char *string) 191 { 192 size_t len = strlen(string); 193 char buf[HEX_DIGEST_LENGTH]; 194 195 if (qflag) 196 printf("%s\n", alg->Data(string, len, buf)); 197 else if (rflag) 198 printf("%s \"%s\"\n", alg->Data(string, len, buf), string); 199 else 200 printf("%s (\"%s\") = %s\n", alg->name, string, alg->Data(string, len, buf)); 201 } 202 /* 203 * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. 204 */ 205 static void 206 MDTimeTrial(Algorithm_t *alg) 207 { 208 DIGEST_CTX context; 209 struct rusage before, after; 210 struct timeval total; 211 float seconds; 212 unsigned char block[TEST_BLOCK_LEN]; 213 unsigned int i; 214 char *p, buf[HEX_DIGEST_LENGTH]; 215 216 printf 217 ("%s time trial. Digesting %d %d-byte blocks ...", 218 alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN); 219 fflush(stdout); 220 221 /* Initialize block */ 222 for (i = 0; i < TEST_BLOCK_LEN; i++) 223 block[i] = (unsigned char) (i & 0xff); 224 225 /* Start timer */ 226 getrusage(0, &before); 227 228 /* Digest blocks */ 229 alg->Init(&context); 230 for (i = 0; i < TEST_BLOCK_COUNT; i++) 231 alg->Update(&context, block, TEST_BLOCK_LEN); 232 p = alg->End(&context, buf); 233 234 /* Stop timer */ 235 getrusage(0, &after); 236 timersub(&after.ru_utime, &before.ru_utime, &total); 237 seconds = total.tv_sec + (float) total.tv_usec / 1000000; 238 239 printf(" done\n"); 240 printf("Digest = %s", p); 241 printf("\nTime = %f seconds\n", seconds); 242 printf 243 ("Speed = %f bytes/second\n", 244 (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds); 245 } 246 /* 247 * Digests a reference suite of strings and prints the results. 248 */ 249 250 const char *MDTestInput[MDTESTCOUNT] = { 251 "", 252 "a", 253 "abc", 254 "message digest", 255 "abcdefghijklmnopqrstuvwxyz", 256 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 257 "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 258 "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \ 259 that its security is in some doubt" 260 }; 261 262 const char *MD5TestOutput[MDTESTCOUNT] = { 263 "d41d8cd98f00b204e9800998ecf8427e", 264 "0cc175b9c0f1b6a831c399e269772661", 265 "900150983cd24fb0d6963f7d28e17f72", 266 "f96b697d7cb7938d525a2f31aaf161d0", 267 "c3fcd3d76192e4007dfb496cca67e13b", 268 "d174ab98d277d9f5a5611c2c9f419d9f", 269 "57edf4a22be3c955ac49da2e2107b67a", 270 "b50663f41d44d92171cb9976bc118538" 271 }; 272 273 const char *SHA1_TestOutput[MDTESTCOUNT] = { 274 "da39a3ee5e6b4b0d3255bfef95601890afd80709", 275 "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", 276 "a9993e364706816aba3e25717850c26c9cd0d89d", 277 "c12252ceda8be8994d5fa0290a47231c1d16aae3", 278 "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", 279 "761c457bf73b14d27e9e9265c46f4b4dda11f940", 280 "50abf5706a150990a08b2c5ea40fa0e585554732", 281 "18eca4333979c4181199b7b4fab8786d16cf2846" 282 }; 283 284 const char *RIPEMD160_TestOutput[MDTESTCOUNT] = { 285 "9c1185a5c5e9fc54612808977ee8f548b2258d31", 286 "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", 287 "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", 288 "5d0689ef49d2fae572b881b123a85ffa21595f36", 289 "f71c27109c692c1b56bbdceb5b9d2865b3708dbc", 290 "b0e20b6e3116640286ed3a87a5713079b21f5189", 291 "9b752e45573d4b39f4dbd3323cab82bf63326bfb", 292 "5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32" 293 }; 294 295 static void 296 MDTestSuite(Algorithm_t *alg) 297 { 298 int i; 299 char buffer[HEX_DIGEST_LENGTH]; 300 301 printf("%s test suite:\n", alg->name); 302 for (i = 0; i < MDTESTCOUNT; i++) { 303 (*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer); 304 printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer); 305 if (strcmp(buffer, (*alg->TestOutput)[i]) == 0) 306 printf(" - verified correct\n"); 307 else 308 printf(" - INCORRECT RESULT!\n"); 309 } 310 } 311 312 /* 313 * Digests the standard input and prints the result. 314 */ 315 static void 316 MDFilter(Algorithm_t *alg, int tee) 317 { 318 DIGEST_CTX context; 319 unsigned int len; 320 unsigned char buffer[BUFSIZ]; 321 char buf[HEX_DIGEST_LENGTH]; 322 323 alg->Init(&context); 324 while ((len = fread(buffer, 1, BUFSIZ, stdin))) { 325 if (tee && len != fwrite(buffer, 1, len, stdout)) 326 err(1, "stdout"); 327 alg->Update(&context, buffer, len); 328 } 329 printf("%s\n", alg->End(&context, buf)); 330 } 331 332 static void 333 usage(Algorithm_t *alg) 334 { 335 336 fprintf(stderr, "usage: %s [-pqrtx] [-s string] [files ...]\n", alg->progname); 337 exit(1); 338 } 339