md5.c revision 110840
16562Sphk/* 237421Scharnier * Derived from: 36562Sphk * 46562Sphk * MDDRIVER.C - test driver for MD2, MD4 and MD5 53995Spst */ 63995Spst 76562Sphk/* 86562Sphk * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All 96562Sphk * rights reserved. 106562Sphk * 116562Sphk * RSA Data Security, Inc. makes no representations concerning either 126562Sphk * the merchantability of this software or the suitability of this 136562Sphk * software for any particular purpose. It is provided "as is" 146562Sphk * without express or implied warranty of any kind. 156562Sphk * 166562Sphk * These notices must be retained in any copies of any part of this 176562Sphk * documentation and/or software. 183995Spst */ 193995Spst 2037421Scharnier#ifndef lint 2137421Scharnierstatic const char rcsid[] = 2250476Speter "$FreeBSD: head/sbin/md5/md5.c 110840 2003-02-14 04:48:06Z silby $"; 2337421Scharnier#endif /* not lint */ 2437421Scharnier 2519168Sbde#include <sys/types.h> 26110840Ssilby#include <sys/time.h> 27110840Ssilby#include <sys/resource.h> 2837421Scharnier#include <err.h> 2919168Sbde#include <md5.h> 303995Spst#include <stdio.h> 3178949Sdes#include <stdlib.h> 3278949Sdes#include <string.h> 333995Spst#include <time.h> 3432074Ssteve#include <unistd.h> 3519168Sbde 366562Sphk/* 376562Sphk * Length of test block, number of test blocks. 383995Spst */ 3946226Skris#define TEST_BLOCK_LEN 10000 4046226Skris#define TEST_BLOCK_COUNT 100000 413995Spst 4254109Sobrienint qflag; 4352949Sobrienint rflag; 4488226Sphkint sflag; 4552949Sobrien 4676988Srustatic void MDString(const char *); 4776988Srustatic void MDTimeTrial(void); 4876988Srustatic void MDTestSuite(void); 4976988Srustatic void MDFilter(int); 5076988Srustatic void usage(void); 513995Spst 523995Spst/* Main driver. 533995Spst 543995SpstArguments (may be any combination): 553995Spst -sstring - digests string 563995Spst -t - runs time trial 573995Spst -x - runs test script 583995Spst filename - digests file 593995Spst (none) - digests standard input 603995Spst */ 616562Sphkint 6276988Srumain(int argc, char *argv[]) 633995Spst{ 6432086Ssteve int ch; 656562Sphk char *p; 669489Sphk char buf[33]; 673995Spst 6878756Sru while ((ch = getopt(argc, argv, "pqrs:tx")) != -1) 6976988Sru switch (ch) { 7076988Sru case 'p': 7176988Sru MDFilter(1); 7276988Sru break; 7376988Sru case 'q': 7476988Sru qflag = 1; 7576988Sru break; 7676988Sru case 'r': 7776988Sru rflag = 1; 7876988Sru break; 7976988Sru case 's': 8088226Sphk sflag = 1; 8176988Sru MDString(optarg); 8276988Sru break; 8376988Sru case 't': 8476988Sru MDTimeTrial(); 8576988Sru break; 8676988Sru case 'x': 8776988Sru MDTestSuite(); 8876988Sru break; 8976988Sru default: 9076988Sru usage(); 9132074Ssteve } 9276988Sru argc -= optind; 9376988Sru argv += optind; 9476988Sru 9576988Sru if (*argv) { 9676988Sru do { 9776988Sru p = MD5File(*argv, buf); 9832074Ssteve if (!p) 9976988Sru warn("%s", *argv); 10032074Ssteve else 10154109Sobrien if (qflag) 10254109Sobrien printf("%s\n", p); 10354109Sobrien else if (rflag) 10476988Sru printf("%s %s\n", p, *argv); 10552949Sobrien else 10676988Sru printf("MD5 (%s) = %s\n", *argv, p); 10776988Sru } while (*++argv); 10888226Sphk } else if (!sflag && (optind == 1 || qflag || rflag)) 1096725Sphk MDFilter(0); 1103995Spst 1116562Sphk return (0); 1123995Spst} 1136562Sphk/* 1146562Sphk * Digests a string and prints the result. 1153995Spst */ 1166562Sphkstatic void 11776988SruMDString(const char *string) 1183995Spst{ 11948953Sbillf size_t len = strlen(string); 1209489Sphk char buf[33]; 1213995Spst 12254109Sobrien if (qflag) 12354109Sobrien printf("%s\n", MD5Data(string, len, buf)); 12454109Sobrien else if (rflag) 12553092Sobrien printf("%s \"%s\"\n", MD5Data(string, len, buf), string); 12652949Sobrien else 12752949Sobrien printf("MD5 (\"%s\") = %s\n", string, MD5Data(string, len, buf)); 1283995Spst} 1296562Sphk/* 1306562Sphk * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. 1313995Spst */ 1326562Sphkstatic void 13376988SruMDTimeTrial(void) 1343995Spst{ 1356562Sphk MD5_CTX context; 136110840Ssilby struct rusage before, after; 137110840Ssilby struct timeval total; 138110840Ssilby float seconds; 1396725Sphk unsigned char block[TEST_BLOCK_LEN]; 1406562Sphk unsigned int i; 1419489Sphk char *p, buf[33]; 1423995Spst 1436562Sphk printf 1446562Sphk ("MD5 time trial. Digesting %d %d-byte blocks ...", 14521763Sphk TEST_BLOCK_COUNT, TEST_BLOCK_LEN); 14646226Skris fflush(stdout); 1473995Spst 1486562Sphk /* Initialize block */ 1496562Sphk for (i = 0; i < TEST_BLOCK_LEN; i++) 1506562Sphk block[i] = (unsigned char) (i & 0xff); 1513995Spst 1526562Sphk /* Start timer */ 153110840Ssilby getrusage(0, &before); 1543995Spst 1556562Sphk /* Digest blocks */ 1566562Sphk MD5Init(&context); 1576562Sphk for (i = 0; i < TEST_BLOCK_COUNT; i++) 1586562Sphk MD5Update(&context, block, TEST_BLOCK_LEN); 1599489Sphk p = MD5End(&context,buf); 1603995Spst 1616562Sphk /* Stop timer */ 162110840Ssilby getrusage(0, &after); 163110840Ssilby timersub(&after.ru_utime, &before.ru_utime, &total); 164110840Ssilby seconds = total.tv_sec + (float) total.tv_usec / 1000000; 1653995Spst 1666562Sphk printf(" done\n"); 1676562Sphk printf("Digest = %s", p); 168110840Ssilby printf("\nTime = %f seconds\n", seconds); 1696562Sphk printf 170110840Ssilby ("Speed = %f bytes/second\n", 171110840Ssilby (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds); 1723995Spst} 1736562Sphk/* 1746562Sphk * Digests a reference suite of strings and prints the results. 1753995Spst */ 176109870Ssilby 177109870Ssilby#define MD5TESTCOUNT 8 178109870Ssilby 179109870Ssilbychar *MDTestInput[] = { 180109870Ssilby "", 181109870Ssilby "a", 182109870Ssilby "abc", 183109870Ssilby "message digest", 184109870Ssilby "abcdefghijklmnopqrstuvwxyz", 185109870Ssilby "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 186109870Ssilby "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 187109870Ssilby "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made that its security is in some doubt" 188109870Ssilby}; 189109870Ssilby 190109870Ssilbychar *MDTestOutput[MD5TESTCOUNT] = { 191109870Ssilby "d41d8cd98f00b204e9800998ecf8427e", 192109870Ssilby "0cc175b9c0f1b6a831c399e269772661", 193109870Ssilby "900150983cd24fb0d6963f7d28e17f72", 194109870Ssilby "f96b697d7cb7938d525a2f31aaf161d0", 195109870Ssilby "c3fcd3d76192e4007dfb496cca67e13b", 196109870Ssilby "d174ab98d277d9f5a5611c2c9f419d9f", 197109870Ssilby "57edf4a22be3c955ac49da2e2107b67a", 198109870Ssilby "b50663f41d44d92171cb9976bc118538" 199109870Ssilby}; 200109870Ssilby 2016562Sphkstatic void 20276988SruMDTestSuite(void) 2033995Spst{ 204109870Ssilby int i; 205109870Ssilby char buffer[33]; 20632086Ssteve 2076562Sphk printf("MD5 test suite:\n"); 208109870Ssilby for (i = 0; i < MD5TESTCOUNT; i++) { 209109870Ssilby MD5Data(MDTestInput[i], strlen(MDTestInput[i]), buffer); 210109870Ssilby printf("MD5 (\"%s\") = %s", MDTestInput[i], buffer); 211109870Ssilby if (strcmp(buffer, MDTestOutput[i]) == 0) 212109870Ssilby printf(" - verified correct\n"); 213109870Ssilby else 214109870Ssilby printf(" - INCORRECT RESULT!\n"); 215109870Ssilby } 2163995Spst} 2173995Spst 2186562Sphk/* 2196562Sphk * Digests the standard input and prints the result. 2203995Spst */ 2216562Sphkstatic void 22276988SruMDFilter(int tee) 2233995Spst{ 2246562Sphk MD5_CTX context; 22576988Sru unsigned int len; 22632074Ssteve unsigned char buffer[BUFSIZ]; 2279489Sphk char buf[33]; 2283995Spst 2296562Sphk MD5Init(&context); 23032074Ssteve while ((len = fread(buffer, 1, BUFSIZ, stdin))) { 23176988Sru if (tee && len != fwrite(buffer, 1, len, stdout)) 23237421Scharnier err(1, "stdout"); 2336562Sphk MD5Update(&context, buffer, len); 2346725Sphk } 2359489Sphk printf("%s\n", MD5End(&context,buf)); 2363995Spst} 23732074Ssteve 23832074Sstevestatic void 23976988Sruusage(void) 24032074Ssteve{ 24132086Ssteve 24268503Sobrien fprintf(stderr, "usage: md5 [-pqrtx] [-s string] [files ...]\n"); 24332074Ssteve exit(1); 24432074Ssteve} 245