raw
keksum_genesis_3        1 /* Standalone KECCAK hashing utility
keksum_genesis_3 2 * J. Welsh, May 2019
keksum_genesis_3 3 */
keksum_genesis_3 4
keksum_genesis_3 5 #include <fcntl.h>
keksum_genesis_3 6 #include <signal.h>
keksum_genesis_3 7 #include <unistd.h>
keksum_genesis_3 8 #include "io.h"
keksum_genesis_3 9
keksum_genesis_3 10 void sponge(unsigned capacity, size_t out_bits);
keksum_genesis_3 11
keksum_genesis_3 12 #pragma GCC diagnostic ignored "-Woverlength-strings" /* wat. */
keksum_genesis_3 13
keksum_genesis_3 14 static char const usage[] =
keksum_genesis_3 15 "Usage: keksum [-c] [-sCAPACITY] [-nLENGTH] [-h] [--] [FILE]...\n"
keksum_genesis_3 16 "Compute KECCAK checksums.\n"
keksum_genesis_3 17 "\n"
keksum_genesis_3 18 "With no FILE, act as a filter, reading from standard input then printing\n"
keksum_genesis_3 19 "a single line containing the hex-encoded hash. Otherwise tabulate hash and\n"
keksum_genesis_3 20 "name for each FILE.\n"
keksum_genesis_3 21 "\n"
keksum_genesis_3 22 "Options:\n"
keksum_genesis_3 23 " -c read sums from FILEs and check them (TODO)\n"
keksum_genesis_3 24 " -l set output length in bits (default 512)\n"
keksum_genesis_3 25 " -s set sponge capacity in bits (default 256)\n"
keksum_genesis_3 26 " -h print this help and exit\n"
keksum_genesis_3 27 "\n"
keksum_genesis_3 28 "Capacity and length both establish upper bounds on security level. Capacity\n"
keksum_genesis_3 29 "strongly affects speed and hash by changing permutation frequency. Length\n"
keksum_genesis_3 30 "acts as a truncation of an infinite output stream. (If you use large length\n"
keksum_genesis_3 31 "with small capacity you will be deluding yourself in quite the same manner\n"
keksum_genesis_3 32 "as a poorly seeded PRNG.) Both must be multiples of 8. The 1600-bit\n"
keksum_genesis_3 33 "permutation is always used, thus capacity must be between 8 and 1592.\n";
keksum_genesis_3 34
keksum_genesis_3 35 static void usage_err(char const *msg) {
keksum_genesis_3 36 write_line(2,msg);
keksum_genesis_3 37 write_str(2,usage);
keksum_genesis_3 38 _exit(1);
keksum_genesis_3 39 }
keksum_genesis_3 40
keksum_genesis_3 41 static unsigned dec_value(unsigned char c) {
keksum_genesis_3 42 unsigned r = c-'0';
keksum_genesis_3 43 if (r > 9) usage_err(c ? "Bad integer" : "Missing integer value");
keksum_genesis_3 44 return r;
keksum_genesis_3 45 }
keksum_genesis_3 46
keksum_genesis_3 47 static unsigned parse_uint(char const *s) {
keksum_genesis_3 48 unsigned acc = dec_value(*s++);
keksum_genesis_3 49 if (!acc && *s) usage_err("Bad integer (leading zero)");
keksum_genesis_3 50 for (; *s; ++s) {
keksum_genesis_3 51 unsigned digit = dec_value(*s);
keksum_genesis_3 52 if (acc > ((unsigned) -1)/10)
keksum_genesis_3 53 usage_err("Integer out of range");
keksum_genesis_3 54 acc *= 10;
keksum_genesis_3 55 if (acc > ((unsigned) -1) - digit)
keksum_genesis_3 56 usage_err("Integer out of range");
keksum_genesis_3 57 acc += digit;
keksum_genesis_3 58 }
keksum_genesis_3 59 return acc;
keksum_genesis_3 60 }
keksum_genesis_3 61
keksum_genesis_3 62 int main(int argc, char **argv) {
keksum_genesis_3 63 unsigned out_len = 512;
keksum_genesis_3 64 /* Rationale: for collision resistance, any hash function needs at
keksum_genesis_3 65 * least twice the desired security level in non-redundant output bits
keksum_genesis_3 66 * due to the birthday problem. */
keksum_genesis_3 67
keksum_genesis_3 68 unsigned capacity = 256;
keksum_genesis_3 69 /* Rationale: sponge capacity is an upper bound on security level
keksum_genesis_3 70 * because the permutation is readily inverted if its full output is
keksum_genesis_3 71 * known. Beyond that, its relationship to actual security is not clear
keksum_genesis_3 72 * to me (or perhaps anyone); some margin of safety seems prudent. The
keksum_genesis_3 73 * EuCrypt default is 256 (bitrate 1344). But note that in the FIPS202
keksum_genesis_3 74 * parameters, capacity under 512 is seen only in "SHAKE128" and none
keksum_genesis_3 75 * of the "SHA3" fixed-width hashes. See also:
keksum_genesis_3 76 * http://fixpoint.welshcomputing.com/keksum-a-keccak-imp/#comments */
keksum_genesis_3 77
keksum_genesis_3 78 signal(SIGPIPE,SIG_IGN); /* standard unix-hate */
keksum_genesis_3 79
keksum_genesis_3 80 #define SHIFT (--argc, ++argv)
keksum_genesis_3 81 if (!argc) goto endopts;
keksum_genesis_3 82 for (SHIFT; argc; SHIFT) {
keksum_genesis_3 83 char const *arg = *argv;
keksum_genesis_3 84 if (arg[0] != '-') goto endopts;
keksum_genesis_3 85 switch (arg[1]) {
keksum_genesis_3 86 case 0: goto endopts;
keksum_genesis_3 87 case 'l': out_len = parse_uint(arg+2); break;
keksum_genesis_3 88 case 's': capacity = parse_uint(arg+2); break;
keksum_genesis_3 89 case 'h': write_str(1,usage); return 0;
keksum_genesis_3 90 case '-': if (!arg[2]) { SHIFT; goto endopts; }
keksum_genesis_3 91 /* fallthrough */
keksum_genesis_3 92 default: usage_err("Bad option");
keksum_genesis_3 93 }
keksum_genesis_3 94 }
keksum_genesis_3 95 endopts:
keksum_genesis_3 96 if (out_len&7) usage_err("Length not byte-aligned");
keksum_genesis_3 97 if (capacity&7) usage_err("Capacity not byte-aligned");
keksum_genesis_3 98 if (!(0 < capacity && capacity < 1600))
keksum_genesis_3 99 usage_err("Capacity out of range");
keksum_genesis_3 100
keksum_genesis_3 101 if (argc) {
keksum_genesis_3 102 /* Listing is similar to the GNU (?) format but with no input
keksum_genesis_3 103 * mode character (you may know this as the mysterious extra
keksum_genesis_3 104 * space): it's always binary. */
keksum_genesis_3 105 for (; argc; SHIFT) {
keksum_genesis_3 106 int fd = chkp(*argv, open(*argv, O_RDONLY));
keksum_genesis_3 107 chkp("dup2", dup2(fd,0));
keksum_genesis_3 108 chkp("close", close(fd));
keksum_genesis_3 109 sponge(capacity,out_len);
keksum_genesis_3 110 write_str(1," ");
keksum_genesis_3 111 write_line(1,*argv);
keksum_genesis_3 112 }
keksum_genesis_3 113 }
keksum_genesis_3 114 else {
keksum_genesis_3 115 sponge(capacity,out_len);
keksum_genesis_3 116 newline(1);
keksum_genesis_3 117 }
keksum_genesis_3 118 return 0;
keksum_genesis_3 119 }