1 /* 2 * Derived from: 3 * 4 * MDDRIVER.C - test driver for MD2, MD4 and MD5 5 */ 6 7 /* 8 * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All 9 * rights reserved. 10 * 11 * RSA Data Security, Inc. makes no representations concerning either 12 * the merchantability of this software or the suitability of this 13 * software for any particular purpose. It is provided "as is" 14 * without express or implied warranty of any kind. 15 * 16 * These notices must be retained in any copies of any part of this 17 * documentation and/or software. 18 */ 19 20 #ifndef lint 21 static const char rcsid[] = 22 "$FreeBSD$"; 23 #endif /* not lint */ 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 <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <time.h> 34 #include <unistd.h> 35 36 /* 37 * Length of test block, number of test blocks. 38 */ 39 #define TEST_BLOCK_LEN 10000 40 #define TEST_BLOCK_COUNT 100000 41 42 int qflag; 43 int rflag; 44 int sflag; 45 46 static void MDString(const char *); 47 static void MDTimeTrial(void); 48 static void MDTestSuite(void); 49 static void MDFilter(int); 50 static void usage(void); 51 52 /* Main driver. 53 54 Arguments (may be any combination): 55 -sstring - digests string 56 -t - runs time trial 57 -x - runs test script 58 filename - digests file 59 (none) - digests standard input 60 */ 61 int 62 main(int argc, char *argv[]) 63 { 64 int ch; 65 char *p; 66 char buf[33]; 67 68 while ((ch = getopt(argc, argv, "pqrs:tx")) != -1) 69 switch (ch) { 70 case 'p': 71 MDFilter(1); 72 break; 73 case 'q': 74 qflag = 1; 75 break; 76 case 'r': 77 rflag = 1; 78 break; 79 case 's': 80 sflag = 1; 81 MDString(optarg); 82 break; 83 case 't': 84 MDTimeTrial(); 85 break; 86 case 'x': 87 MDTestSuite(); 88 break; 89 default: 90 usage(); 91 } 92 argc -= optind; 93 argv += optind; 94 95 if (*argv) { 96 do { 97 p = MD5File(*argv, buf); 98 if (!p) 99 warn("%s", *argv); 100 else 101 if (qflag) 102 printf("%s\n", p); 103 else if (rflag) 104 printf("%s %s\n", p, *argv); 105 else 106 printf("MD5 (%s) = %s\n", *argv, p); 107 } while (*++argv); 108 } else if (!sflag && (optind == 1 || qflag || rflag)) 109 MDFilter(0); 110 111 return (0); 112 } 113 /* 114 * Digests a string and prints the result. 115 */ 116 static void 117 MDString(const char *string) 118 { 119 size_t len = strlen(string); 120 char buf[33]; 121 122 if (qflag) 123 printf("%s\n", MD5Data(string, len, buf)); 124 else if (rflag) 125 printf("%s \"%s\"\n", MD5Data(string, len, buf), string); 126 else 127 printf("MD5 (\"%s\") = %s\n", string, MD5Data(string, len, buf)); 128 } 129 /* 130 * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. 131 */ 132 static void 133 MDTimeTrial(void) 134 { 135 MD5_CTX context; 136 struct rusage before, after; 137 struct timeval total; 138 float seconds; 139 unsigned char block[TEST_BLOCK_LEN]; 140 unsigned int i; 141 char *p, buf[33]; 142 143 printf 144 ("MD5 time trial. Digesting %d %d-byte blocks ...", 145 TEST_BLOCK_COUNT, TEST_BLOCK_LEN); 146 fflush(stdout); 147 148 /* Initialize block */ 149 for (i = 0; i < TEST_BLOCK_LEN; i++) 150 block[i] = (unsigned char) (i & 0xff); 151 152 /* Start timer */ 153 getrusage(0, &before); 154 155 /* Digest blocks */ 156 MD5Init(&context); 157 for (i = 0; i < TEST_BLOCK_COUNT; i++) 158 MD5Update(&context, block, TEST_BLOCK_LEN); 159 p = MD5End(&context,buf); 160 161 /* Stop timer */ 162 getrusage(0, &after); 163 timersub(&after.ru_utime, &before.ru_utime, &total); 164 seconds = total.tv_sec + (float) total.tv_usec / 1000000; 165 166 printf(" done\n"); 167 printf("Digest = %s", p); 168 printf("\nTime = %f seconds\n", seconds); 169 printf 170 ("Speed = %f bytes/second\n", 171 (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds); 172 } 173 /* 174 * Digests a reference suite of strings and prints the results. 175 */ 176 177 #define MD5TESTCOUNT 8 178 179 char *MDTestInput[] = { 180 "", 181 "a", 182 "abc", 183 "message digest", 184 "abcdefghijklmnopqrstuvwxyz", 185 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 186 "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 187 "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made that its security is in some doubt" 188 }; 189 190 char *MDTestOutput[MD5TESTCOUNT] = { 191 "d41d8cd98f00b204e9800998ecf8427e", 192 "0cc175b9c0f1b6a831c399e269772661", 193 "900150983cd24fb0d6963f7d28e17f72", 194 "f96b697d7cb7938d525a2f31aaf161d0", 195 "c3fcd3d76192e4007dfb496cca67e13b", 196 "d174ab98d277d9f5a5611c2c9f419d9f", 197 "57edf4a22be3c955ac49da2e2107b67a", 198 "b50663f41d44d92171cb9976bc118538" 199 }; 200 201 static void 202 MDTestSuite(void) 203 { 204 int i; 205 char buffer[33]; 206 207 printf("MD5 test suite:\n"); 208 for (i = 0; i < MD5TESTCOUNT; i++) { 209 MD5Data(MDTestInput[i], strlen(MDTestInput[i]), buffer); 210 printf("MD5 (\"%s\") = %s", MDTestInput[i], buffer); 211 if (strcmp(buffer, MDTestOutput[i]) == 0) 212 printf(" - verified correct\n"); 213 else 214 printf(" - INCORRECT RESULT!\n"); 215 } 216 } 217 218 /* 219 * Digests the standard input and prints the result. 220 */ 221 static void 222 MDFilter(int tee) 223 { 224 MD5_CTX context; 225 unsigned int len; 226 unsigned char buffer[BUFSIZ]; 227 char buf[33]; 228 229 MD5Init(&context); 230 while ((len = fread(buffer, 1, BUFSIZ, stdin))) { 231 if (tee && len != fwrite(buffer, 1, len, stdout)) 232 err(1, "stdout"); 233 MD5Update(&context, buffer, len); 234 } 235 printf("%s\n", MD5End(&context,buf)); 236 } 237 238 static void 239 usage(void) 240 { 241 242 fprintf(stderr, "usage: md5 [-pqrtx] [-s string] [files ...]\n"); 243 exit(1); 244 } 245