?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  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. #include <sys/param.h>
  22. #include <sys/resource.h>
  23. #include <sys/stat.h>
  24. #include <sys/time.h>
  25.  
  26. #include <err.h>
  27. #include <errno.h>
  28. #include <fcntl.h>
  29. #include <getopt.h>
  30. #include <stdbool.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <stdint.h>
  34. #include <string.h>
  35. #include <time.h>
  36. #include <unistd.h>
  37. #include <limits.h>
  38. #include <alloca.h>
  39.  
  40. #include "hash-common.h"
  41. #include "md5-my.h"
  42. #include "sphash-opt.h"
  43.  
  44.  
  45. /*
  46.  * Length of test block, number of test blocks.
  47.  */
  48. #define TEST_BLOCK_LEN 10000
  49. #define TEST_BLOCK_COUNT 100000
  50.  
  51. static char *progname;
  52.  
  53. static bool cflag;
  54. static bool pflag;
  55. static bool qflag;
  56. static bool sflag;
  57. static bool wflag;
  58. static bool strict;
  59. static bool skip;
  60. static bool ignoreMissing;
  61. static char* checkAgainst;
  62. static int checksFailed;
  63. static bool failed;
  64. static int endl = '\n';
  65.  
  66. typedef void (DIGEST_Init)(void *);
  67. typedef void (DIGEST_Update)(void *, const unsigned char *, size_t);
  68. typedef char *(DIGEST_End)(void *, char *);
  69.  
  70. /*
  71.  * Digests a reference suite of strings and prints the results.
  72.  */
  73.  
  74. static const char * MD5TestInput[] =
  75. {
  76.         "",
  77.         "a",
  78.         "abc",
  79.         "message digest",
  80.         "abcdefghijklmnopqrstuvwxyz",
  81.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
  82.         "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
  83.         "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made that its security is in some doubt",
  84.         NULL
  85. };
  86.  
  87. static const char *MD5TestOutput[] = {
  88.         "d41d8cd98f00b204e9800998ecf8427e",
  89.         "0cc175b9c0f1b6a831c399e269772661",
  90.         "900150983cd24fb0d6963f7d28e17f72",
  91.         "f96b697d7cb7938d525a2f31aaf161d0",
  92.         "c3fcd3d76192e4007dfb496cca67e13b",
  93.         "d174ab98d277d9f5a5611c2c9f419d9f",
  94.         "57edf4a22be3c955ac49da2e2107b67a",
  95.         "b50663f41d44d92171cb9976bc118538",
  96.         NULL
  97. };
  98.  
  99.  
  100.         // test generated by gen_tests.py for sphash64
  101. static const char * SPEHTestInput[] =
  102. {
  103.         "",
  104.         "A",
  105.         "AB",
  106.         "ABC",
  107.         "ABCD",
  108.         "ABCDE",
  109.         "ABCDEF",
  110.         "ABCDEFG",
  111.         "ABCDEFGH",
  112.         "ABCDEFGHI",
  113.         "ABCDEFGHIJ",
  114.         "ABCDEFGHIJK",
  115.         "ABCDEFGHIJKL",
  116.         "ABCDEFGHIJKLM",
  117.         "ABCDEFGHIJKLMN",
  118.         "ABCDEFGHIJKLMNO",
  119.         "ABCDEFGHIJKLMNOP",
  120.         "ABCDEFGHIJKLMNOPQ",
  121.         "ABCDEFGHIJKLMNOPQR",
  122.         "ABCDEFGHIJKLMNOPQRS",
  123.         "ABCDEFGHIJKLMNOPQRST",
  124.         "ABCDEFGHIJKLMNOPQRSTU",
  125.         "ABCDEFGHIJKLMNOPQRSTUV",
  126.         "ABCDEFGHIJKLMNOPQRSTUVW",
  127.         "ABCDEFGHIJKLMNOPQRSTUVWX",
  128.         "ABCDEFGHIJKLMNOPQRSTUVWXY",
  129.         "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  130.         "ABCDEFGHIJKLMNOPQRSTUVWXYZa",
  131.         "ABCDEFGHIJKLMNOPQRSTUVWXYZab",
  132.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabc",
  133.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcd",
  134.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcde",
  135.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef",
  136.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg",
  137.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh",
  138.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi",
  139.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij",
  140.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk",
  141.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl",
  142.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm",
  143.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn",
  144.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmno",
  145.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop",
  146.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq",
  147.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr",
  148.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs",
  149.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst",
  150.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu",
  151.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv",
  152.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw",
  153.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx",
  154.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy",
  155.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
  156.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0",
  157.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01",
  158.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012",
  159.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123",
  160.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234",
  161.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345",
  162.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456",
  163.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567",
  164.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678",
  165.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
  166.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+",
  167.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
  168.         NULL
  169. };
  170.  
  171. static const char * SPEHTestOutput[] =
  172. {
  173.         "d41a687aa4cc0943",
  174.         "2a5e7dce9268795d",
  175.         "2aa32aff120c8bbd",
  176.         "4cc834eba8232eff",
  177.         "b5f630638324d3d0",
  178.         "00d62e62cae9f9aa",
  179.         "1f4834059da5176d",
  180.         "cdb55e07b6adef31",
  181.         "2e75f39fc807fc23",
  182.         "796d9cbe9113139d",
  183.         "2ce8adc2c851ecb0",
  184.         "16328a6d67b91749",
  185.         "8f27ee28db11432e",
  186.         "ff8ebd80fc4901af",
  187.         "eda4273c5a25c6d1",
  188.         "6b67eabf1b45e35d",
  189.         "30fbf5f7554cf5f6",
  190.         "441277d3fa663352",
  191.         "075f3895c302f7e6",
  192.         "f059391fade7d419",
  193.         "5401b2d5de6fbb8f",
  194.         "ad875ef54d37659a",
  195.         "f6a62b2c5acfbcc7",
  196.         "7e738c42b144a6ec",
  197.         "931f490123fa354e",
  198.         "e82cccbd86e7dd4f",
  199.         "572e7b43b67ffebe",
  200.         "d6f63e1bec142428",
  201.         "9ff11a98d3c79da1",
  202.         "41cfff1465fadc46",
  203.         "6f0bd77654c97b23",
  204.         "014679bed5d79c5e",
  205.         "bc0eb42ef70f0530",
  206.         "7168d2bb8489a157",
  207.         "07f9fa4feb64ee94",
  208.         "a1060236ec6e090e",
  209.         "6451656f2d230af5",
  210.         "102c41241065be1d",
  211.         "bb53b43e2ab6ad8f",
  212.         "af000b355ac99cdd",
  213.         "cb74fb56e86f169f",
  214.         "c4f71bbd90e1c866",
  215.         "4645b03e95fc5ed1",
  216.         "002b72b7c78c2cc1",
  217.         "fe024cae6d090c47",
  218.         "14579a258878555a",
  219.         "fff3397c52e4b7db",
  220.         "7bbc08da4d8e8903",
  221.         "77ea369c4b08a0b1",
  222.         "4400ccb28853a79d",
  223.         "f7c15c3e1e620555",
  224.         "6e6f45b3738fb494",
  225.         "7a04997feed34fe2",
  226.         "99693a218e8ce8fd",
  227.         "73073e23cf74c1d8",
  228.         "9cf1bc4696913db8",
  229.         "04c3ed98a67396fe",
  230.         "467d233497ad8129",
  231.         "3521b52e730ae695",
  232.         "d2ed4d776c5911a8",
  233.         "eacc8b2cbf189b0a",
  234.         "61ce1c0d71c89483",
  235.         "c1d826c0eb85c37e",
  236.         "39f4b728293a6dba",
  237.         "fb51a133ac079c54",
  238.         NULL
  239. };
  240.  
  241.  
  242.  
  243. typedef struct Algorithm_t {
  244.         const char *progname;
  245.         const char *perlname;
  246.         const char *name;
  247.        
  248.         const char ** TestInput;
  249.         const char ** TestOutput;
  250.  
  251.         struct hash_iface * (*make_hash)(void);
  252.         struct hash_iface * hash;
  253. } Algorithm_t;
  254.  
  255. //static void MD5_Update(DIGEST_CTX *, const unsigned char *, size_t);
  256. static char *MDInput(const Algorithm_t *, FILE *, char *, bool);
  257. static void MDOutput(const Algorithm_t *, char *, const char *);
  258. static void TimeTrial(const Algorithm_t *);
  259. static void TestSuite(const Algorithm_t *);
  260. static void usage(const Algorithm_t *);
  261. static void version(void);
  262.  
  263.  
  264. typedef struct hash_iface * DIGEST_CTX;
  265.  
  266.  
  267.  
  268. /* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
  269.         SHA256_DIGEST_LENGTH, SHA512_DIGEST_LENGTH,
  270.         RIPEMD160_DIGEST_LENGTH, SKEIN1024_DIGEST_LENGTH)*2+1 */
  271. #define HEX_DIGEST_LENGTH 257
  272.  
  273. /* algorithm function table */
  274.  
  275. static struct Algorithm_t Algorithm[] =
  276. {
  277.         {
  278.                 "md5", NULL, "MD5",
  279.                 MD5TestInput,
  280.                 MD5TestOutput,
  281.                 &make_md5_my,
  282.                 NULL
  283.         },
  284.  
  285.         {
  286.                 "speh", NULL, "SPEH",
  287.                 SPEHTestInput,
  288.                 SPEHTestOutput,
  289.                 &make_sphash_opt,
  290.                 NULL
  291.         },
  292.  
  293.         { }
  294. };
  295.  
  296.  
  297. static char * dataToHex(const Algorithm_t * alg, const uint8_t * msg, size_t len, char * strbuf); // same as MD5Data but uses Algorithm_t with hash_iface * in it to generate hash
  298. static char * convToHex(const Algorithm_t * alg, char * strbus);
  299.  
  300.  
  301. static int digest = -1;
  302. static unsigned int malformed;
  303.  
  304. static enum mode {
  305.         mode_bsd,
  306.         mode_gnu,
  307.         mode_perl,
  308. } mode = mode_bsd;
  309.  
  310. static enum input_mode {
  311.         input_binary     = '*',
  312.         input_text       = ' ',
  313.         input_universal  = 'U',
  314.         input_bits       = '^',
  315. } input_mode = input_binary;
  316.  
  317. static enum output_mode {
  318.         output_bare,
  319.         output_tagged,
  320.         output_reverse,
  321.         output_gnu,
  322. } output_mode = output_tagged;
  323.  
  324. enum optval {
  325.         opt_end = -1,
  326.         /* ensure we don't collide with shortopts */
  327.         opt_dummy = CHAR_MAX,
  328.         /* BSD options */
  329.         opt_check,
  330.         opt_passthrough,
  331.         opt_quiet,
  332.         opt_reverse,
  333.         opt_string,
  334.         opt_time_trial,
  335.         opt_self_test,
  336.         /* GNU options */
  337.         opt_binary,
  338.         opt_help,
  339.         opt_ignore_missing,
  340.         opt_status,
  341.         opt_strict,
  342.         opt_tag,
  343.         opt_text,
  344.         opt_warn,
  345.         opt_version,
  346.         opt_zero,
  347.         /* Perl options */
  348.         opt_algorithm,
  349.         opt_bits,
  350.         opt_universal,
  351. };
  352.  
  353. static const struct option bsd_longopts[] = {
  354.         { "check",              required_argument,      0, opt_check },
  355.         { "passthrough",        no_argument,            0, opt_passthrough },
  356.         { "quiet",              no_argument,            0, opt_quiet },
  357.         { "reverse",            no_argument,            0, opt_reverse },
  358.         { "string",             required_argument,      0, opt_string },
  359.         { "time-trial",         no_argument,            0, opt_time_trial },
  360.         { "self-test",          no_argument,            0, opt_self_test },
  361.         { }
  362. };
  363. static const char *bsd_shortopts = "bc:pqrs:tx";
  364.  
  365. static const struct option gnu_longopts[] = {
  366.         { "binary",             no_argument,            0, opt_binary },
  367.         { "check",              no_argument,            0, opt_check },
  368.         { "help",               no_argument,            0, opt_help },
  369.         { "ignore-missing",     no_argument,            0, opt_ignore_missing },
  370.         { "quiet",              no_argument,            0, opt_quiet },
  371.         { "status",             no_argument,            0, opt_status },
  372.         { "strict",             no_argument,            0, opt_strict },
  373.         { "tag",                no_argument,            0, opt_tag },
  374.         { "text",               no_argument,            0, opt_text },
  375.         { "version",            no_argument,            0, opt_version },
  376.         { "warn",               no_argument,            0, opt_warn },
  377.         { "zero",               no_argument,            0, opt_zero },
  378.         { }
  379. };
  380. static const char *gnu_shortopts = "bctwz";
  381.  
  382. static const struct option perl_longopts[] = {
  383.         { "algorithm",          required_argument,      0, opt_algorithm },
  384.         { "check",              required_argument,      0, opt_check },
  385.         { "help",               no_argument,            0, opt_help },
  386.         { "ignore-missing",     no_argument,            0, opt_ignore_missing },
  387.         { "quiet",              no_argument,            0, opt_quiet },
  388.         { "status",             no_argument,            0, opt_status },
  389.         { "strict",             no_argument,            0, opt_strict },
  390.         { "tag",                no_argument,            0, opt_tag },
  391.         { "text",               no_argument,            0, opt_text },
  392.         { "UNIVERSAL",          no_argument,            0, opt_universal },
  393.         { "version",            no_argument,            0, opt_version },
  394.         { "warn",               no_argument,            0, opt_warn },
  395.         { "01",                 no_argument,            0, opt_bits },
  396.         { }
  397. };
  398. static const char *perl_shortopts = "0a:bchqstUvw";
  399.  
  400. //static void
  401. //MD5_Update(DIGEST_CTX *c, const unsigned char *data, size_t len)
  402. //{
  403. //      MD5Update(c, data, len);
  404. //}
  405.  
  406. struct chksumrec {
  407.         char    *filename;
  408.         char    *chksum;
  409.         struct  chksumrec       *next;
  410. };
  411.  
  412. static struct chksumrec *head = NULL;
  413. static struct chksumrec **next = &head;
  414. static unsigned int numrecs;
  415.  
  416. #define PADDING 7       /* extra padding for "SHA512t256 (...) = ...\n" style */
  417. #define CHKFILELINELEN  (HEX_DIGEST_LENGTH + MAXPATHLEN + PADDING)
  418.  
  419. static void
  420. gnu_check(const char *checksumsfile)
  421. {
  422.         FILE    *inp;
  423.         char    *linebuf = NULL;
  424.         size_t  linecap;
  425.         ssize_t linelen;
  426.         int     lineno;
  427.         char    *filename;
  428.         char    *hashstr;
  429.         struct chksumrec        *rec;
  430.         const char      *digestname;
  431.         size_t  digestnamelen;
  432.         size_t  hashstrlen;
  433.  
  434.         if (strcmp(checksumsfile, "-") == 0)
  435.                 inp = stdin;
  436.         else if ((inp = fopen(checksumsfile, "r")) == NULL)
  437.                 err(1, "%s", checksumsfile);
  438.         digestname = Algorithm[digest].name;
  439.         digestnamelen = strlen(digestname);
  440.         hashstrlen = strlen((Algorithm[digest].TestOutput)[0]);
  441.         lineno = 0;
  442.         linecap = CHKFILELINELEN;
  443.         while ((linelen = getline(&linebuf, &linecap, inp)) > 0) {
  444.                 lineno++;
  445.                 while (linelen > 0 && linebuf[linelen - 1] == '\n')
  446.                         linelen--;
  447.                 linebuf[linelen] = '\0';
  448.                 filename = linebuf + digestnamelen + 2;
  449.                 hashstr = linebuf + linelen - hashstrlen;
  450.                 /*
  451.                  * supported formats:
  452.                  * BSD: <DigestName> (<Filename>): <Digest>
  453.                  * GNU: <Digest> [ *U^]<Filename>
  454.                  */
  455.                 if ((size_t)linelen >= digestnamelen + hashstrlen + 6 &&
  456.                     strncmp(linebuf, digestname, digestnamelen) == 0 &&
  457.                     strncmp(filename - 2, " (", 2) == 0 &&
  458.                     strncmp(hashstr - 4, ") = ", 4) == 0 &&
  459.                     strspn(hashstr, "0123456789ABCDEFabcdef") == hashstrlen) {
  460.                         *(hashstr - 4) = '\0';
  461.                 } else if ((size_t)linelen >= hashstrlen + 3 &&
  462.                     strspn(linebuf, "0123456789ABCDEFabcdef") == hashstrlen &&
  463.                     linebuf[hashstrlen] == ' ') {
  464.                         linebuf[hashstrlen] = '\0';
  465.                         hashstr = linebuf;
  466.                         filename = linebuf + hashstrlen + 1;
  467.                 } else {
  468.                         if (wflag) {
  469.                                 warnx("%s: %d: improperly formatted "
  470.                                     "%s checksum line",
  471.                                     checksumsfile, lineno,
  472.                                     mode == mode_perl ? "SHA" : digestname);
  473.                         }
  474.                         malformed++;
  475.                         continue;
  476.                 }
  477.                 rec = malloc(sizeof(*rec));
  478.                 if (rec == NULL)
  479.                         errx(1, "malloc failed");
  480.                 rec->chksum = strdup(hashstr);
  481.                 rec->filename = strdup(filename);
  482.                 if (rec->chksum == NULL || rec->filename == NULL)
  483.                         errx(1, "malloc failed");
  484.                 rec->next = NULL;
  485.                 *next = rec;
  486.                 next = &rec->next;
  487.                 numrecs++;
  488.         }
  489.         if (inp != stdin)
  490.                 fclose(inp);
  491. }
  492.  
  493. /* Main driver.
  494.  
  495. Arguments (may be any combination):
  496.   -sstring - digests string
  497.   -t       - runs time trial
  498.   -x       - runs test script
  499.   filename - digests file
  500.   (none)   - digests standard input
  501.  */
  502. int
  503. main(int argc, char *argv[])
  504. {
  505.         const struct option *longopts;
  506.         const char *shortopts;
  507.         FILE   *f;
  508.         int     i, opt;
  509.         char   *p, *string = NULL;
  510.         char    buf[HEX_DIGEST_LENGTH];
  511.         size_t  len;
  512.         struct chksumrec        *rec;
  513.  
  514.         if ((progname = strrchr(argv[0], '/')) == NULL)
  515.                 progname = argv[0];
  516.         else
  517.                 progname++;
  518.  
  519.         /*
  520.          * GNU coreutils has a number of programs named *sum. These produce
  521.          * similar results to the BSD version, but in a different format,
  522.          * similar to BSD's -r flag. We install links to this program with
  523.          * ending 'sum' to provide this compatibility. Check here to see if the
  524.          * name of the program ends in 'sum', set the flag and drop the 'sum' so
  525.          * the digest lookup works. Also, make -t a nop when running in this mode
  526.          * since that means 'text file' there (though it's a nop in coreutils
  527.          * on unix-like systems). The -c flag conflicts, so it's just disabled
  528.          * in this mode (though in the future it might be implemented).
  529.          *
  530.          * We also strive to be compatible with the shasum script which is
  531.          * included in Perl.  It is roughly equivalent to the GNU offering
  532.          * but uses a command-line argument to select the algorithm, and
  533.          * supports only SHA-1 and SHA-2.
  534.          */
  535.         len = strlen(progname);
  536.         if (strcmp(progname, "shasum") == 0) {
  537.                 mode = mode_perl;
  538.                 input_mode = input_text;
  539.                 output_mode = output_gnu;
  540.                 digest = 1;
  541.                 longopts = perl_longopts;
  542.                 shortopts = perl_shortopts;
  543.         } else if (len > 3 && strcmp(progname + len - 3, "sum") == 0) {
  544.                 len -= 3;
  545.                 mode = mode_gnu;
  546.                 input_mode = input_text;
  547.                 /*
  548.                  * The historical behavior in GNU emulation mode is
  549.                  * output_reverse, however this not true to the original
  550.                  * and the flag that was used to force the correct output
  551.                  * was -b, which means something else (input_binary) in
  552.                  * GNU land.  Switch to the correct behavior.
  553.                  */
  554.                 output_mode = output_gnu;
  555.                 longopts = gnu_longopts;
  556.                 shortopts = gnu_shortopts;
  557.         } else {
  558.                 mode = mode_bsd;
  559.                 input_mode = input_binary;
  560.                 output_mode = output_tagged;
  561.                 longopts = bsd_longopts;
  562.                 shortopts = bsd_shortopts;
  563.         }
  564.  
  565.        
  566.         // initialize algorithms
  567.         for( Algorithm_t * a = Algorithm; a->make_hash; a++ )
  568.         {
  569.                 a->hash = (*a->make_hash)();
  570.                 if( !a->hash )
  571.                 {
  572.                         fprintf(stderr, "couldn't run (a->make_hash)()\n");
  573.                         exit(1);
  574.                 }
  575.  
  576.                 if( !(*a->hash->hash_init)(a->hash) )
  577.                 {
  578.                         fprintf(stderr, "(a->make_hash->hash_init)() failed\n");
  579.                         exit(1);
  580.                 }
  581.         }
  582.  
  583.  
  584.         if (digest < 0) {
  585.                 for (digest = 0; Algorithm[digest].progname != NULL; digest++)
  586.                         if (strncasecmp(Algorithm[digest].progname, progname, len) == 0)
  587.                                 break;
  588.  
  589.                 if (Algorithm[digest].progname == NULL)
  590.                         digest = 0;
  591.         }
  592.  
  593.         failed = false;
  594.         checkAgainst = NULL;
  595.         checksFailed = 0;
  596.         skip = false;
  597.         while ((opt = getopt_long(argc, argv, shortopts, longopts, NULL)) != opt_end)
  598.                 switch (opt) {
  599.                 case opt_bits:
  600.                 case '0':
  601.                         input_mode = input_bits;
  602.                         break;
  603.                 case opt_algorithm:
  604.                 case 'a':
  605.                         for (i = 0; Algorithm[i].progname != NULL; i++) {
  606.                                 if (Algorithm[i].perlname != NULL &&
  607.                                     strcasecmp(Algorithm[i].perlname, optarg) == 0) {
  608.                                         digest = i;
  609.                                         break;
  610.                                 }
  611.                         }
  612.                         if (Algorithm[i].progname == NULL)
  613.                                 usage(&Algorithm[digest]);
  614.                         break;
  615.                 case opt_binary:
  616.                 case 'b':
  617.                         /* in BSD mode, -b is now a no-op */
  618.                         if (mode != mode_bsd)
  619.                                 input_mode = input_binary;
  620.                         break;
  621.                 case opt_check:
  622.                 case 'c':
  623.                         cflag = true;
  624.                         if (mode == mode_bsd)
  625.                                 checkAgainst = optarg;
  626.                         break;
  627.                 case opt_passthrough:
  628.                 case 'p':
  629.                         pflag = true;
  630.                         break;
  631.                 case opt_quiet:
  632.                 case 'q':
  633.                         output_mode = output_bare;
  634.                         qflag = true;
  635.                         break;
  636.                 case opt_reverse:
  637.                 case 'r':
  638.                         if (!qflag)
  639.                                 output_mode = output_reverse;
  640.                         break;
  641.                 case opt_status:
  642.                         sflag = true;
  643.                         break;
  644.                 case opt_strict:
  645.                         strict = 1;
  646.                         break;
  647.                 case 's':
  648.                         if (mode == mode_perl) {
  649.                                 sflag = true;
  650.                                 break;
  651.                         }
  652.                         /* fall through */
  653.                 case opt_string:
  654.                         output_mode = output_bare;
  655.                         string = optarg;
  656.                         break;
  657.                 case opt_tag:
  658.                         output_mode = output_tagged;
  659.                         break;
  660.                 case opt_time_trial:
  661.                 case opt_text:
  662.                 case 't':
  663.                         if (mode == mode_bsd) {
  664.                                 TimeTrial(&Algorithm[digest]);
  665.                                 skip = true;
  666.                         } else {
  667.                                 input_mode = input_text;
  668.                         }
  669.                         break;
  670.                 case opt_universal:
  671.                 case 'U':
  672.                         input_mode = input_universal;
  673.                         break;
  674.                 case opt_version:
  675.                         version();
  676.                         break;
  677.                 case opt_warn:
  678.                 case 'w':
  679.                         wflag = true;
  680.                         break;
  681.                 case opt_self_test:
  682.                 case 'x':
  683.                         TestSuite(&Algorithm[digest]);
  684.                         skip = true;
  685.                         break;
  686.                 case opt_zero:
  687.                 case 'z':
  688.                         endl = '\0';
  689.                         break;
  690.                 case opt_ignore_missing:
  691.                         ignoreMissing = true;
  692.                         break;
  693.                 default:
  694.                         usage(&Algorithm[digest]);
  695.                 }
  696.         argc -= optind;
  697.         argv += optind;
  698.  
  699.  
  700.         if (cflag && mode != mode_bsd) {
  701.                 /*
  702.                  * Read digest files into a linked list, then replace argv
  703.                  * with an array of the filenames from that list.
  704.                  */
  705.                 if (argc < 1)
  706.                         usage(&Algorithm[digest]);
  707.                 while (argc--)
  708.                         gnu_check(*argv++);
  709.                 argc = 0;
  710.                 argv = calloc(sizeof(char *), numrecs + 1);
  711.                 for (rec = head; rec != NULL; rec = rec->next) {
  712.                         argv[argc] = rec->filename;
  713.                         argc++;
  714.                 }
  715.                 argv[argc] = NULL;
  716.                 rec = head;
  717.         }
  718.  
  719.         if (*argv) {
  720.                 do {
  721.                         struct stat st;
  722.                         const char *filename = *argv;
  723.                         const char *filemode = "rb";
  724.  
  725.                         if (*filename == '*' ||
  726.                             *filename == ' ' ||
  727.                             *filename == 'U' ||
  728.                             *filename == '^') {
  729.                                 if (lstat(filename, &st) != 0) {
  730.                                         input_mode = (int)*filename;
  731.                                         filename++;
  732.                                 }
  733.                         }
  734.                         if (input_mode == input_text)
  735.                                 filemode = "r";
  736.                         if ((f = fopen(filename, filemode)) == NULL) {
  737.                                 if (errno != ENOENT || !(cflag && ignoreMissing)) {
  738.                                         warn("%s", filename);
  739.                                         failed = true;
  740.                                 }
  741.                                 if (cflag && mode != mode_bsd)
  742.                                         rec = rec->next;
  743.                                 continue;
  744.                         }
  745.                         /*
  746.                          * XXX Enter capability mode on the last argv file.
  747.                          * When a casper file service or other approach is
  748.                          * available, switch to that and enter capability mode
  749.                          * earlier.
  750.                          */
  751.                         if (*(argv + 1) == NULL) {
  752.                         }
  753.                         if (cflag && mode != mode_bsd) {
  754.                                 checkAgainst = rec->chksum;
  755.                                 rec = rec->next;
  756.                         }
  757.                         p = MDInput(&Algorithm[digest], f, buf, false);
  758.                         (void)fclose(f);
  759.                         MDOutput(&Algorithm[digest], p, filename);
  760.                 } while (*++argv);
  761.         } else if (!cflag && string == NULL && !skip) {
  762.                 if (mode == mode_bsd)
  763.                         output_mode = output_bare;
  764.                 p = MDInput(&Algorithm[digest], stdin, buf, pflag);
  765.                 MDOutput(&Algorithm[digest], p, "-");
  766.         } else if (string != NULL) {
  767.                 len = strlen(string);
  768.  
  769. //              p = Algorithm[digest].Data(string, len, buf);
  770.                 p = dataToHex(&Algorithm[digest], string, len, buf);
  771.  
  772.                 MDOutput(&Algorithm[digest], p, string);
  773.         }
  774.         if (cflag && mode != mode_bsd) {
  775.                 if (!sflag && malformed > 1)
  776.                         warnx("WARNING: %d lines are improperly formatted", malformed);
  777.                 else if (!sflag && malformed > 0)
  778.                         warnx("WARNING: %d line is improperly formatted", malformed);
  779.                 if (!sflag && checksFailed > 1)
  780.                         warnx("WARNING: %d computed checksums did NOT match", checksFailed);
  781.                 else if (!sflag && checksFailed > 0)
  782.                         warnx("WARNING: %d computed checksum did NOT match", checksFailed);
  783.                 if (checksFailed != 0 || (strict && malformed > 0))
  784.                         return (1);
  785.         }
  786.         if (failed)
  787.                 return (1);
  788.         if (checksFailed > 0)
  789.                 return (2);
  790.  
  791.         return (0);
  792. }
  793.  
  794. /*
  795.  * Common input handling
  796.  */
  797. static char *
  798. MDInput(const Algorithm_t *alg, FILE *f, char *buf, bool tee)
  799. {
  800.         char block[4096];
  801.         DIGEST_CTX context;
  802.         char *end, *p, *q;
  803.         size_t len;
  804.         int bits;
  805.         uint8_t byte;
  806.         bool cr = false;
  807.  
  808. //      alg->Init(&context);
  809.         alg->hash->hash_start(alg->hash);
  810.         while ((len = fread(block, 1, sizeof(block), f)) > 0) {
  811.                 switch (input_mode) {
  812.                 case input_binary:
  813.                 case input_text:
  814.                         if (tee && fwrite(block, 1, len, stdout) != len)
  815.                                 err(1, "stdout");
  816.  
  817. //                      alg->Update(&context, block, len);
  818.                         alg->hash->hash_addbytes(alg->hash, block, len);
  819.  
  820.                         break;
  821.                 case input_universal:
  822.                         end = block + len;
  823.                         for (p = q = block; p < end; p = q) {
  824.                                 if (cr) {
  825.                                         if (*p == '\n')
  826.                                                 p++;
  827.                                         if (tee && putchar('\n') == EOF)
  828.                                                 err(1, "stdout");
  829.  
  830. //                                      alg->Update(&context, "\n", 1);
  831.                                         alg->hash->hash_addbytes(alg->hash, "\n", 1);
  832.  
  833.                                         cr = false;
  834.                                 }
  835.                                 for (q = p; q < end && *q != '\r'; q++)
  836.                                         /* nothing */;
  837.                                 if (q > p) {
  838.                                         if (tee &&
  839.                                             fwrite(p, 1, q - p, stdout) !=
  840.                                             (size_t)(q - p))
  841.                                                 err(1, "stdout");
  842.  
  843. //                                      alg->Update(&context, p, q - p);
  844.                                         alg->hash->hash_addbytes(alg->hash, p, q-p);
  845.  
  846.                                 }
  847.                                 if (q < end && *q == '\r') {
  848.                                         cr = true;
  849.                                         q++;
  850.                                 }
  851.                         }
  852.                         break;
  853.                 case input_bits:
  854.                         end = block + len;
  855.                         bits = byte = 0;
  856.                         for (p = block; p < end; p++) {
  857.                                 if (*p == '0' || *p == '1') {
  858.                                         byte <<= 1;
  859.                                         byte |= *p - '0';
  860.                                         if (++bits == 8) {
  861.                                                 if (tee && putchar(byte) == EOF)
  862.                                                         err(1, "stdout");
  863.  
  864. //                                              alg->Update(&context, &byte, 1);
  865.                                                 alg->hash->hash_addbytes(alg->hash, &byte, 1);
  866.  
  867.                                                 bits = byte = 0;
  868.                                         }
  869.                                 }
  870.                         }
  871.                         break;
  872.                 }
  873.         }
  874.         if (ferror(f)) {
  875.  
  876. //              alg->End(&context, buf);
  877.                 convToHex(alg, buf);
  878.  
  879.                 return (NULL);
  880.         }
  881.         if (cr) {
  882.                 if (tee && putchar('\n') == EOF)
  883.                         err(1, "stdout");
  884.  
  885. //              alg->Update(&context, "\n", 1);
  886.                 alg->hash->hash_addbytes(alg->hash, "\n", 1);
  887.  
  888.         }
  889.         if (input_mode == input_bits && bits != 0)
  890.                 errx(1, "input length was not a multiple of 8");
  891.  
  892. //      return (alg->End(&context, buf));
  893.         return convToHex(alg, buf);
  894.  
  895. }
  896.  
  897. /*
  898.  * Common output handling
  899.  */
  900. static void
  901. MDOutput(const Algorithm_t *alg, char *p, const char *name)
  902. {
  903.         bool checkfailed = false;
  904.  
  905.         if (p == NULL) {
  906.                 warn("%s", name);
  907.                 failed = true;
  908.         } else if (cflag && mode != mode_bsd) {
  909.                 checkfailed = strcasecmp(checkAgainst, p) != 0;
  910.                 if (!sflag && (!qflag || checkfailed))
  911.                         printf("%s: %s%c", name, checkfailed ? "FAILED" : "OK",
  912.                             endl);
  913.         } else {
  914.                 switch (output_mode) {
  915.                 case output_bare:
  916.                         printf("%s", p);
  917.                         break;
  918.                 case output_gnu:
  919.                         printf("%s %c%s", p, input_mode, name);
  920.                         break;
  921.                 case output_reverse:
  922.                         printf("%s %s", p, name);
  923.                         break;
  924.                 case output_tagged:
  925.                         if (mode == mode_perl &&
  926.                             strncmp(alg->name, "SHA512t", 7) == 0) {
  927.                                 printf("%.6s/%s", alg->name, alg->name + 7);
  928.                         } else {
  929.                                 printf("%s", alg->name);
  930.                         }
  931.                         printf(" (%s) = %s", name, p);
  932.                         break;
  933.                 }
  934.                 if (checkAgainst) {
  935.                         checkfailed = strcasecmp(checkAgainst, p) != 0;
  936.                         if (!qflag && checkfailed)
  937.                                 printf(" [ Failed ]");
  938.                 }
  939.                 printf("%c", endl);
  940.         }
  941.         if (checkfailed)
  942.                 checksFailed++;
  943. }
  944.  
  945. /*
  946.  * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
  947.  */
  948. static void
  949. TimeTrial(const Algorithm_t *alg)
  950. {
  951.         DIGEST_CTX context;
  952.         struct rusage before, after;
  953.         struct timeval total;
  954.         float seconds;
  955.         unsigned char block[TEST_BLOCK_LEN];
  956.         unsigned int i;
  957.         char *p, buf[HEX_DIGEST_LENGTH];
  958.  
  959.         printf("%s time trial. Digesting %d %d-byte blocks ...",
  960.             alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
  961.         fflush(stdout);
  962.  
  963.         /* Initialize block */
  964.         for (i = 0; i < TEST_BLOCK_LEN; i++)
  965.                 block[i] = (unsigned char) (i & 0xff);
  966.  
  967.         /* Start timer */
  968.         getrusage(RUSAGE_SELF, &before);
  969.  
  970.         /* Digest blocks */
  971.  
  972. //      alg->Init(&context);
  973.         alg->hash->hash_start(alg->hash);
  974.  
  975.         for (i = 0; i < TEST_BLOCK_COUNT; i++)
  976.                 //alg->Update(&context, block, TEST_BLOCK_LEN);
  977.                 alg->hash->hash_addbytes(alg->hash, block, TEST_BLOCK_LEN);
  978.  
  979.         //p = alg->End(&context, buf);
  980.         p = convToHex(alg, buf);
  981.  
  982.         /* Stop timer */
  983.         getrusage(RUSAGE_SELF, &after);
  984.         timersub(&after.ru_utime, &before.ru_utime, &total);
  985.         seconds = total.tv_sec + (float) total.tv_usec / 1000000;
  986.  
  987.         printf(" done\n");
  988.         printf("Digest = %s", p);
  989.         printf("\nTime = %f seconds\n", seconds);
  990.         printf("Speed = %f MiB/second\n", (float) TEST_BLOCK_LEN *
  991.                 (float) TEST_BLOCK_COUNT / seconds / (1 << 20));
  992. }
  993.  
  994.  
  995. static void
  996. TestSuite(const Algorithm_t *alg)
  997. {
  998.         int i;
  999.         char buffer[HEX_DIGEST_LENGTH];
  1000.  
  1001.         printf("%s test suite:\n", alg->name);
  1002.  
  1003.         const char ** in_arr;
  1004.         const char ** out_arr;
  1005.  
  1006.         in_arr  = alg->TestInput;
  1007.         out_arr = alg->TestOutput;
  1008.  
  1009.         while( *in_arr && *out_arr )
  1010.         {
  1011.         //for (i = 0; i < MDTESTCOUNT; i++) {
  1012.                 //(*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer);
  1013.                 dataToHex(alg, *in_arr, strlen(*in_arr), buffer);
  1014.                 printf("%s (\"%s\") = %s", alg->name, *in_arr, buffer);
  1015.                 if (strcmp(buffer, *out_arr) == 0) {
  1016.                         printf(" - verified correct\n");
  1017.                 } else {
  1018.                         printf(" - INCORRECT RESULT!\n");
  1019.                         failed = true;
  1020.                 }
  1021.                 in_arr++;
  1022.                 out_arr++;
  1023.         }
  1024. }
  1025.  
  1026. static void
  1027. usage(const Algorithm_t *alg)
  1028. {
  1029.  
  1030.         switch (mode) {
  1031.         case mode_gnu:
  1032.                 fprintf(stderr, "usage: %ssum [-bctwz] [files ...]\n", alg->progname);
  1033.                 break;
  1034.         case mode_perl:
  1035.                 fprintf(stderr, "usage: shasum [-0bchqstUvw] [-a alg] [files ...]\n");
  1036.                 break;
  1037.         default:
  1038.                 fprintf(stderr, "usage: %s [-pqrtx] [-c string] [-s string] [files ...]\n",
  1039.                     alg->progname);
  1040.         }
  1041.         exit(1);
  1042. }
  1043.  
  1044. static void
  1045. version(void)
  1046. {
  1047.         if (mode == mode_gnu)
  1048.                 printf("%s (FreeBSD) ", progname);
  1049.         exit(0);
  1050. }
  1051.  
  1052.  
  1053. static char * dataToHex(const Algorithm_t * alg, const uint8_t * msg, size_t len, char * strbuf)
  1054. {
  1055.         struct hash_iface * h = alg->hash;
  1056.  
  1057.         h->hash_start(h);
  1058.         h->hash_addbytes(h,msg,len);
  1059.  
  1060.         return convToHex(alg, strbuf);
  1061. }
  1062.  
  1063. static char * convToHex(const Algorithm_t * alg, char * strbuf)
  1064. {
  1065.         struct hash_iface * h = alg->hash;
  1066.  
  1067.         size_t hlen = h->hash_getsize(h);
  1068.         size_t slen = hlen*2+1; // string len, incl. \0
  1069.  
  1070.         uint8_t * result = alloca(hlen);
  1071.  
  1072.         h->hash_result(h,result);
  1073.  
  1074.         if( !strbuf )
  1075.                 strbuf = (char *) malloc( slen );
  1076.         if( !strbuf )
  1077.                 return NULL;
  1078.        
  1079.         const char hex[]="0123456789abcdef";
  1080.        
  1081.         for(size_t i=0;i<hlen;i++)
  1082.         {
  1083.                 strbuf[2*i]   = hex[result[i]>>4];
  1084.                 strbuf[2*i+1] = hex[result[i]&15];
  1085.         }
  1086.         strbuf[slen-1]=0;
  1087.  
  1088.         return strbuf;
  1089. }
  1090.  
  1091.