home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / os2 / pgp263.arj / PGP263I.SRC / PGP263II.ZIP / contrib / md5sum / md5sum.c < prev    next >
C/C++ Source or Header  |  1988-01-11  |  6KB  |  260 lines

  1. /*
  2.  * md5sum.c    - Generate/check MD5 Message Digests
  3.  *
  4.  * Compile and link with md5.c.  If you don't have getopt() in your library
  5.  * also include getopt.c.  For MSDOS you can also link with the wildcard
  6.  * initialization function (wildargs.obj for Turbo C and setargv.obj for MSC)
  7.  * so that you can use wildcards on the commandline.
  8.  *
  9.  * Make sure that you compile with -DHIGHFIRST if you are on a big-endian
  10.  * system. Here are some examples of correct MD5 sums:
  11.  * 
  12.  * % echo "The meeting last week was swell." | md5sum
  13.  * 050f3905211cddf36107ffc361c23e3d
  14.  *  
  15.  * % echo 'There is $1500 in the blue box.' | md5sum
  16.  * 05f8cfc03f4e58cbee731aa4a14b3f03
  17.  *
  18.  * If you get anything else than this, then you've done something wrong. ;)
  19.  *
  20.  * Written March 1993 by Branko Lankester
  21.  * Modified June 1993 by Colin Plumb for altered md5.c.
  22.  */
  23. #include <stdlib.h>    /* Added RKNOP 960111 */
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include "md5.h"
  27. #ifdef AMIGA           /* Added RKNOP 960111 */
  28. #include "getopt.h"
  29. #define getopt(a,b,c) pgp_getopt((a),(b),(c))
  30. #endif
  31.  
  32. #ifdef UNIX
  33. #define    FOPRTXT    "r"
  34. #define    FOPRBIN    "r"
  35. #else
  36. #ifdef VMS
  37. #define    FOPRTXT    "r","ctx=stm"
  38. #define    FOPRBIN    "rb","ctx=stm"
  39. #else
  40. #define    FOPRTXT    "r"
  41. #define    FOPRBIN    "rb"
  42. #endif
  43. #endif
  44.  
  45. extern char *optarg;
  46. extern int optind;
  47.  
  48. void usage();
  49. void print_digest();
  50. int mdfile(FILE *fp, unsigned char *digest);
  51. int do_check(FILE *chkf);
  52.  
  53. char *progname;
  54. int verbose = 0;
  55. int bin_mode = 0;
  56.  
  57. void
  58. main(int argc, char **argv)
  59. {
  60.     int opt, rc = 0;
  61.     int check = 0;
  62.     FILE *fp;
  63.     unsigned char digest[16];
  64.  
  65.     progname = *argv;
  66.     while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) {
  67.         switch (opt) {
  68.             case 'c': check = 1; break;
  69.             case 'v': verbose = 1; break;
  70.             case 'b': bin_mode = 1; break;
  71.             default: usage();
  72.         }
  73.     }
  74.     argc -= optind;
  75.     argv += optind;
  76.     if (check) {
  77.         switch (argc) {
  78.             case 0: fp = stdin; break;
  79.             case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) {
  80.                     perror(*argv);
  81.                     exit(2);
  82.                 }
  83.                 break;
  84.             default: usage();
  85.         }
  86.         exit(do_check(fp));
  87.     }
  88.     if (argc == 0) {
  89.         if (mdfile(stdin, digest)) {
  90.             fprintf(stderr, "%s: read error on stdin\n", progname);
  91.             exit(2);
  92.         }
  93.         print_digest(digest);
  94.         printf("\n");
  95.         exit(0);
  96.     }
  97.     for ( ; argc > 0; --argc, ++argv) {
  98.         if (bin_mode)
  99.             fp = fopen(*argv, FOPRBIN);
  100.         else
  101.             fp = fopen(*argv, FOPRTXT);
  102.         if (fp == NULL) {
  103.             perror(*argv);
  104.             rc = 2;
  105.             continue;
  106.         }
  107.         if (mdfile(fp, digest)) {
  108.             fprintf(stderr, "%s: error reading %s\n", progname, *argv);
  109.             rc = 2;
  110.         } else {
  111.             print_digest(digest);
  112.             printf(" %c%s\n", bin_mode ? '*' : ' ', *argv);
  113.         }
  114.         fclose(fp);
  115.     }
  116.     exit(rc);
  117. }
  118.  
  119. void
  120. usage()
  121. {
  122.     fprintf(stderr, "usage: md5sum [-bv] [-c [file]] | [file...]\n");
  123.     fprintf(stderr, "Generates or checks MD5 Message Digests\n");
  124.     fprintf(stderr, "    -c  check message digests (default is generate)\n");
  125.     fprintf(stderr, "    -v  verbose, print file names when checking\n");
  126.     fprintf(stderr, "    -b  read files in binary mode\n");
  127.     fprintf(stderr, "The input for -c should be the list of message digests and file names\n");
  128.     fprintf(stderr, "that is printed on stdout by this program when it generates digests.\n");
  129.     exit(2);
  130. }
  131.  
  132. int
  133. mdfile(FILE *fp, unsigned char *digest)
  134. {
  135.     unsigned char buf[1024];
  136.     MD5_CTX ctx;
  137.     int n;
  138.  
  139.     MD5Init(&ctx);
  140.     while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
  141.         MD5Update(&ctx, buf, n);
  142.     MD5Final(digest, &ctx);
  143.     if (ferror(fp))
  144.         return -1;
  145.     return 0;
  146. }
  147.  
  148. void
  149. print_digest(unsigned char *p)
  150. {
  151.     int i;
  152.  
  153.     for (i = 0; i < 16; ++i)
  154.         printf("%02x", *p++);
  155. }
  156.  
  157. int
  158. hex_digit(int c)
  159. {
  160.     if (c >= '0' && c <= '9')
  161.         return c - '0';
  162.     if (c >= 'a' && c <= 'f')
  163.         return c - 'a' + 10;
  164.     return -1;
  165. }
  166.  
  167. int
  168. get_md5_line(FILE *fp, unsigned char *digest, char *file)
  169. {
  170.     char buf[1024];
  171.     int i, d1, d2, rc;
  172.     char *p = buf;
  173.  
  174.     if (fgets(buf, sizeof(buf), fp) == NULL)
  175.         return -1;
  176.  
  177.     for (i = 0; i < 16; ++i) {
  178.         if ((d1 = hex_digit(*p++)) == -1)
  179.             return 0;
  180.         if ((d2 = hex_digit(*p++)) == -1)
  181.             return 0;
  182.         *digest++ = d1*16 + d2;
  183.     }
  184.     if (*p++ != ' ')
  185.         return 0;
  186.     /*
  187.      * next char is an attribute char, space means text file
  188.      * if it's a '*' the file should be checked in binary mode.
  189.      */
  190.     if (*p == ' ')
  191.         rc = 1;
  192.     else if (*p == '*')
  193.         rc = 2;
  194.     else {
  195.         fprintf(stderr, "%s: unrecognized line: %s", progname, buf);
  196.         return 0;
  197.     }
  198.     ++p;
  199.     i = strlen(p);
  200.     if (i < 2 || i > 255)
  201.         return 0;
  202.     p[i-1] = '\0';
  203.     strcpy(file, p);
  204.     return rc;
  205. }
  206.  
  207. int
  208. do_check(FILE *chkf)
  209. {
  210.     int rc, ex = 0, failed = 0, checked = 0;
  211.     unsigned char chk_digest[16], file_digest[16];
  212.     char filename[256];
  213.     FILE *fp;
  214.     int flen = 14;
  215.  
  216.     while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) {
  217.         if (rc == 0)    /* not an md5 line */
  218.             continue;
  219.         if (verbose) {
  220.             if (strlen(filename) > flen)
  221.                 flen = strlen(filename);
  222.             fprintf(stderr, "%-*s ", flen, filename);
  223.         }
  224.         if (bin_mode || rc == 2)
  225.             fp = fopen(filename, FOPRBIN);
  226.         else
  227.             fp = fopen(filename, FOPRTXT);
  228.         if (fp == NULL) {
  229.             fprintf(stderr, "%s: can't open %s\n", progname, filename);
  230.             ex = 2;
  231.             continue;
  232.         }
  233.         if (mdfile(fp, file_digest)) {
  234.             fprintf(stderr, "%s: error reading %s\n", progname, filename);
  235.             ex = 2;
  236.             fclose(fp);
  237.             continue;
  238.         }
  239.         fclose(fp);
  240.         if (memcmp(chk_digest, file_digest, 16) != 0) {
  241.             if (verbose)
  242.                 fprintf(stderr, "FAILED\n");
  243.             else
  244.                 fprintf(stderr, "%s: MD5 check failed for '%s'\n", progname, filename);
  245.             ++failed;
  246.         } else if (verbose)
  247.             fprintf(stderr, "OK\n");
  248.         ++checked;
  249.     }
  250.     if (verbose && failed)
  251.         fprintf(stderr, "%s: %d of %d file(s) failed MD5 check\n", progname, failed, checked);
  252.     if (!checked) {
  253.         fprintf(stderr, "%s: no files checked\n", progname);
  254.         return 3;
  255.     }
  256.     if (!ex && failed)
  257.         ex = 1;
  258.     return ex;
  259. }
  260.