md5.c revision 121914
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#include <sys/cdefs.h> 21__FBSDID("$FreeBSD: head/sbin/md5/md5.c 121914 2003-11-02 23:12:08Z se $"); 22 23#include <sys/types.h> 24#include <sys/time.h> 25#include <sys/resource.h> 26#include <err.h> 27#include <md5.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <time.h> 32#include <unistd.h> 33 34/* 35 * Length of test block, number of test blocks. 36 */ 37#define TEST_BLOCK_LEN 10000 38#define TEST_BLOCK_COUNT 100000 39 40int qflag; 41int rflag; 42int sflag; 43 44static void MDString(const char *); 45static void MDTimeTrial(void); 46static void MDTestSuite(void); 47static void MDFilter(int); 48static void usage(void); 49 50/* Main driver. 51 52Arguments (may be any combination): 53 -sstring - digests string 54 -t - runs time trial 55 -x - runs test script 56 filename - digests file 57 (none) - digests standard input 58 */ 59int 60main(int argc, char *argv[]) 61{ 62 int ch; 63 char *p; 64 char buf[33]; 65 int failed; 66 67 failed = 0; 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 failed++; 101 } else { 102 if (qflag) 103 printf("%s\n", p); 104 else if (rflag) 105 printf("%s %s\n", p, *argv); 106 else 107 printf("MD5 (%s) = %s\n", *argv, p); 108 } 109 } while (*++argv); 110 } else if (!sflag && (optind == 1 || qflag || rflag)) 111 MDFilter(0); 112 113 if (failed != 0) 114 return (1); 115 116 return (0); 117} 118/* 119 * Digests a string and prints the result. 120 */ 121static void 122MDString(const char *string) 123{ 124 size_t len = strlen(string); 125 char buf[33]; 126 127 if (qflag) 128 printf("%s\n", MD5Data(string, len, buf)); 129 else if (rflag) 130 printf("%s \"%s\"\n", MD5Data(string, len, buf), string); 131 else 132 printf("MD5 (\"%s\") = %s\n", string, MD5Data(string, len, buf)); 133} 134/* 135 * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. 136 */ 137static void 138MDTimeTrial(void) 139{ 140 MD5_CTX context; 141 struct rusage before, after; 142 struct timeval total; 143 float seconds; 144 unsigned char block[TEST_BLOCK_LEN]; 145 unsigned int i; 146 char *p, buf[33]; 147 148 printf 149 ("MD5 time trial. Digesting %d %d-byte blocks ...", 150 TEST_BLOCK_COUNT, TEST_BLOCK_LEN); 151 fflush(stdout); 152 153 /* Initialize block */ 154 for (i = 0; i < TEST_BLOCK_LEN; i++) 155 block[i] = (unsigned char) (i & 0xff); 156 157 /* Start timer */ 158 getrusage(0, &before); 159 160 /* Digest blocks */ 161 MD5Init(&context); 162 for (i = 0; i < TEST_BLOCK_COUNT; i++) 163 MD5Update(&context, block, TEST_BLOCK_LEN); 164 p = MD5End(&context,buf); 165 166 /* Stop timer */ 167 getrusage(0, &after); 168 timersub(&after.ru_utime, &before.ru_utime, &total); 169 seconds = total.tv_sec + (float) total.tv_usec / 1000000; 170 171 printf(" done\n"); 172 printf("Digest = %s", p); 173 printf("\nTime = %f seconds\n", seconds); 174 printf 175 ("Speed = %f bytes/second\n", 176 (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds); 177} 178/* 179 * Digests a reference suite of strings and prints the results. 180 */ 181 182#define MD5TESTCOUNT 8 183 184char *MDTestInput[] = { 185 "", 186 "a", 187 "abc", 188 "message digest", 189 "abcdefghijklmnopqrstuvwxyz", 190 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 191 "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 192 "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made that its security is in some doubt" 193}; 194 195char *MDTestOutput[MD5TESTCOUNT] = { 196 "d41d8cd98f00b204e9800998ecf8427e", 197 "0cc175b9c0f1b6a831c399e269772661", 198 "900150983cd24fb0d6963f7d28e17f72", 199 "f96b697d7cb7938d525a2f31aaf161d0", 200 "c3fcd3d76192e4007dfb496cca67e13b", 201 "d174ab98d277d9f5a5611c2c9f419d9f", 202 "57edf4a22be3c955ac49da2e2107b67a", 203 "b50663f41d44d92171cb9976bc118538" 204}; 205 206static void 207MDTestSuite(void) 208{ 209 int i; 210 char buffer[33]; 211 212 printf("MD5 test suite:\n"); 213 for (i = 0; i < MD5TESTCOUNT; i++) { 214 MD5Data(MDTestInput[i], strlen(MDTestInput[i]), buffer); 215 printf("MD5 (\"%s\") = %s", MDTestInput[i], buffer); 216 if (strcmp(buffer, MDTestOutput[i]) == 0) 217 printf(" - verified correct\n"); 218 else 219 printf(" - INCORRECT RESULT!\n"); 220 } 221} 222 223/* 224 * Digests the standard input and prints the result. 225 */ 226static void 227MDFilter(int tee) 228{ 229 MD5_CTX context; 230 unsigned int len; 231 unsigned char buffer[BUFSIZ]; 232 char buf[33]; 233 234 MD5Init(&context); 235 while ((len = fread(buffer, 1, BUFSIZ, stdin))) { 236 if (tee && len != fwrite(buffer, 1, len, stdout)) 237 err(1, "stdout"); 238 MD5Update(&context, buffer, len); 239 } 240 printf("%s\n", MD5End(&context,buf)); 241} 242 243static void 244usage(void) 245{ 246 247 fprintf(stderr, "usage: md5 [-pqrtx] [-s string] [files ...]\n"); 248 exit(1); 249} 250