/* Standalone KECCAK hashing utility * J. Welsh, May 2019 */ #include #include #include #include "io.h" void sponge(unsigned capacity, size_t out_bits); #pragma GCC diagnostic ignored "-Woverlength-strings" /* wat. */ static char const usage[] = "Usage: keksum [-c] [-sCAPACITY] [-nLENGTH] [-h] [--] [FILE]...\n" "Compute KECCAK checksums.\n" "\n" "With no FILE, act as a filter, reading from standard input then printing\n" "a single line containing the hex-encoded hash. Otherwise tabulate hash and\n" "name for each FILE.\n" "\n" "Options:\n" " -c read sums from FILEs and check them (TODO)\n" " -l set output length in bits (default 512)\n" " -s set sponge capacity in bits (default 256)\n" " -h print this help and exit\n" "\n" "Capacity and length both establish upper bounds on security level. Capacity\n" "strongly affects speed and hash by changing permutation frequency. Length\n" "acts as a truncation of an infinite output stream. (If you use large length\n" "with small capacity you will be deluding yourself in quite the same manner\n" "as a poorly seeded PRNG.) Both must be multiples of 8. The 1600-bit\n" "permutation is always used, thus capacity must be between 8 and 1592.\n"; static void usage_err(char const *msg) { write_line(2,msg); write_str(2,usage); _exit(1); } static unsigned dec_value(unsigned char c) { unsigned r = c-'0'; if (r > 9) usage_err(c ? "Bad integer" : "Missing integer value"); return r; } static unsigned parse_uint(char const *s) { unsigned acc = dec_value(*s++); if (!acc && *s) usage_err("Bad integer (leading zero)"); for (; *s; ++s) { unsigned digit = dec_value(*s); if (acc > ((unsigned) -1)/10) usage_err("Integer out of range"); acc *= 10; if (acc > ((unsigned) -1) - digit) usage_err("Integer out of range"); acc += digit; } return acc; } int main(int argc, char **argv) { unsigned out_len = 512; /* Rationale: for collision resistance, any hash function needs at * least twice the desired security level in non-redundant output bits * due to the birthday problem. */ unsigned capacity = 256; /* Rationale: sponge capacity is an upper bound on security level * because the permutation is readily inverted if its full output is * known. Beyond that, its relationship to actual security is not clear * to me (or perhaps anyone); some margin of safety seems prudent. The * EuCrypt default is 256 (bitrate 1344). But note that in the FIPS202 * parameters, capacity under 512 is seen only in "SHAKE128" and none * of the "SHA3" fixed-width hashes. See also: * http://fixpoint.welshcomputing.com/keksum-a-keccak-imp/#comments */ signal(SIGPIPE,SIG_IGN); /* standard unix-hate */ #define SHIFT (--argc, ++argv) if (!argc) goto endopts; for (SHIFT; argc; SHIFT) { char const *arg = *argv; if (arg[0] != '-') goto endopts; switch (arg[1]) { case 0: goto endopts; case 'l': out_len = parse_uint(arg+2); break; case 's': capacity = parse_uint(arg+2); break; case 'h': write_str(1,usage); return 0; case '-': if (!arg[2]) { SHIFT; goto endopts; } /* fallthrough */ default: usage_err("Bad option"); } } endopts: if (out_len&7) usage_err("Length not byte-aligned"); if (capacity&7) usage_err("Capacity not byte-aligned"); if (!(0 < capacity && capacity < 1600)) usage_err("Capacity out of range"); if (argc) { /* Listing is similar to the GNU (?) format but with no input * mode character (you may know this as the mysterious extra * space): it's always binary. */ for (; argc; SHIFT) { int fd = chkp(*argv, open(*argv, O_RDONLY)); chkp("dup2", dup2(fd,0)); chkp("close", close(fd)); sponge(capacity,out_len); write_str(1," "); write_line(1,*argv); } } else { sponge(capacity,out_len); newline(1); } return 0; }