diff options
Diffstat (limited to '')
-rw-r--r-- | cmdline_sha3sum.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/cmdline_sha3sum.c b/cmdline_sha3sum.c new file mode 100644 index 0000000..8fc33fd --- /dev/null +++ b/cmdline_sha3sum.c @@ -0,0 +1,321 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifdef SUPPORT_SHA3 +#include <libkeccak.h> +#endif + + +static void +intopt(long int *valp, char flag, const char *arg) +{ + if (*valp) + usage(); + if (!isdigit(*arg)) + goto invalid; + for (; isdigit(*arg); arg++) { + if (*valp > (LONG_MAX - (*arg & 15)) / 10) + goto invalid; + *valp = *valp * 10 + (*arg & 15); + } + if (*arg || !*valp) { + invalid: + eprintf("invalid value for -%c option, expected integer within [1, %li]", flag, LONG_MAX); + } +} + + +static char * +fmtalgostr(const char *f, long int r, long int c, long int n, long int z) +{ + char *ret, *p; + int len; + len = snprintf(NULL, 0, "%s[r=%li,c=%li,n=%li,z=%li]", f, r, c, n, z); + if (len <= 0) + abort(); + ret = emalloc((size_t)len); + p = stpcpy(ret, f); + *p++ = '['; + if (r) + p += sprintf(p, "r=%li%s", r, (c | n | z) ? "," : ""); + if (c) + p += sprintf(p, "c=%li%s", c, (n | z) ? "," : ""); + if (n) + p += sprintf(p, "n=%li%s", n, z ? "," : ""); + if (z) + p += sprintf(p, "z=%li", z); + *p++ = ']'; + *p = '\0'; + return ret; +} + + +int +cmdline_sha3sum(int argc, char **argv, enum command command, struct config *config, + const char **algostr, enum libhashsum_algorithm *algorithm, char **algostrbuf) +{ + long int r = 0, c = 0, n = 0, s = 0, w = 0, z = 0, bits; + char *arg, *p; + int verbose = 0; +#ifdef SUPPORT_SHA3 + struct libkeccak_generalised_spec gspec; + struct libkeccak_spec spec; + const char *suffix; +#endif + + *algostrbuf = NULL; + + ARGBEGIN { + case 'c': + config->verify = 1; + break; + + case 'w': + config->warn_improper_format = 1; + break; + + case 'z': + config->format &= (enum format)~WITH_LF; + config->format |= WITH_NUL; + break; + + case 'a': + if (command != SHA3SUM) + usage(); + arg = ARG(); + if (!strcmp(arg, "224")) *algostr = "sha3-224", *algorithm = LIBHASHSUM_SHA3_224; + else if (!strcmp(arg, "256")) *algostr = "sha3-256", *algorithm = LIBHASHSUM_SHA3_256; + else if (!strcmp(arg, "384")) *algostr = "sha3-384", *algorithm = LIBHASHSUM_SHA3_384; + else if (!strcmp(arg, "512")) *algostr = "sha3-512", *algorithm = LIBHASHSUM_SHA3_512; + else + eprintf("unsupport value on -a option, expected 224, 256, 384, or 512"); + break; + + case 'b': /* (compat) */ + config->format &= (enum format)~FORMAT_MASK; + config->format |= BINARY; + break; + + case 'l': /* (compat) */ + config->format &= (enum format)~FORMAT_MASK; + config->format |= LOWERCASE_HEX; + break; + + case 'u': /* (compat) */ + config->format &= (enum format)~FORMAT_MASK; + config->format |= UPPERCASE_HEX; + break; + + case 'x': /* (compat) */ + config->hexinput = 1; + break; + + case 'v': /* (compat) */ + verbose = 1; + break; + + case 'R': + intopt(&r, FLAG(), ARG()); + break; + + case 'C': + intopt(&c, FLAG(), ARG()); + break; + + case 'N': + case 'O': /* (compat) */ + intopt(&n, FLAG(), ARG()); + break; + + case 'S': + case 'B': /* (compat) */ + intopt(&s, FLAG(), ARG()); + break; + + case 'Z': + intopt(&z, FLAG(), ARG()); + break; + + case 'W': + p = arg = ARG(); + while (isdigit(*p)) + p++; + if (*arg && !*p) { + intopt(&w, FLAG(), arg); + } else { + arg = parseopts(config, arg, &parseopt_vendor); + if (*arg) + eprintf("unsupported -W options: %s", arg); + } + break; + + default: + usage(); + } ARGEND; + +#ifdef SUPPORT_SHA3 + libkeccak_generalised_spec_initialise(&gspec); +#endif + + switch (*algorithm) { + case LIBHASHSUM_KECCAK: +#ifdef SUPPORT_SHA3 + suffix = ""; +#endif + break; + case LIBHASHSUM_KECCAK_224: bits = 224; goto spec_keccak; + case LIBHASHSUM_KECCAK_256: bits = 256; goto spec_keccak; + case LIBHASHSUM_KECCAK_384: bits = 384; goto spec_keccak; + case LIBHASHSUM_KECCAK_512: bits = 512; spec_keccak: + if (r | c | n | s | w | z) + usage(); +#ifdef SUPPORT_SHA3 + libkeccak_spec_sha3((struct libkeccak_spec *)&gspec, bits); + suffix = ""; +#endif + break; + case LIBHASHSUM_SHA3_224: bits = 224; goto spec_sha3; + case LIBHASHSUM_SHA3_256: bits = 256; goto spec_sha3; + case LIBHASHSUM_SHA3_384: bits = 384; goto spec_sha3; + case LIBHASHSUM_SHA3_512: bits = 512; spec_sha3: + if (r | c | n | s | w | z) + usage(); +#ifdef SUPPORT_SHA3 + libkeccak_spec_sha3((struct libkeccak_spec *)&gspec, bits); + suffix = LIBKECCAK_SHA3_SUFFIX; +#endif + break; + case LIBHASHSUM_SHAKE128: bits = 128; goto spec_shake; + case LIBHASHSUM_SHAKE256: bits = 256; goto spec_shake; + case LIBHASHSUM_SHAKE512: bits = 512; spec_shake: + if (r | c | s | w | z) + usage(); +#ifdef SUPPORT_SHA3 + libkeccak_spec_shake((struct libkeccak_spec *)&gspec, bits, bits); + suffix = LIBKECCAK_SHAKE_SUFFIX; +#endif + break; + case LIBHASHSUM_RAWSHAKE128: bits = 128; goto spec_rawshake; + case LIBHASHSUM_RAWSHAKE256: bits = 256; goto spec_rawshake; + case LIBHASHSUM_RAWSHAKE512: bits = 512; spec_rawshake: + if (r | c | s | w | z) + usage(); +#ifdef SUPPORT_SHA3 + libkeccak_spec_rawshake((struct libkeccak_spec *)&gspec, bits, bits); + suffix = LIBKECCAK_RAWSHAKE_SUFFIX; +#endif + break; + default: + case LIBHASHSUM_MD2: + case LIBHASHSUM_MD4: + case LIBHASHSUM_MD5: + case LIBHASHSUM_RIPEMD_128: + case LIBHASHSUM_RIPEMD_160: + case LIBHASHSUM_RIPEMD_256: + case LIBHASHSUM_RIPEMD_320: + case LIBHASHSUM_SHA0: + case LIBHASHSUM_SHA1: + case LIBHASHSUM_SHA_224: + case LIBHASHSUM_SHA_256: + case LIBHASHSUM_SHA_384: + case LIBHASHSUM_SHA_512: + case LIBHASHSUM_SHA_512_224: + case LIBHASHSUM_SHA_512_256: + case LIBHASHSUM_BLAKE224: + case LIBHASHSUM_BLAKE256: + case LIBHASHSUM_BLAKE384: + case LIBHASHSUM_BLAKE512: + abort(); + } + + z = z ? z : 1U; + +#ifdef SUPPORT_SHA3 + gspec.bitrate = r ? r : gspec.bitrate; + gspec.capacity = c ? c : gspec.capacity; + gspec.output = n ? n : gspec.output; + gspec.state_size = s ? s : gspec.state_size; + gspec.word_size = w ? w : gspec.word_size; + +# define CASE(N, S) case LIBKECCAK_GENERALISED_SPEC_ERROR_##N: eprintf("%s", S) + switch (libkeccak_degeneralise_spec(&gspec, &spec)) { + case 0: + break; + CASE(STATE_NONPOSITIVE, "the state size must be positive"); + CASE(STATE_TOO_LARGE, "the state size is too large, may not exceed 1600"); + CASE(STATE_MOD_25, "the state size must be a multiple of 25"); + CASE(WORD_NONPOSITIVE, "the word size must be positive"); + CASE(WORD_TOO_LARGE, "the word size is too large, may not exceed 64"); + CASE(STATE_WORD_INCOHERENCY, "the state size must be exactly 25 times the word size"); + CASE(CAPACITY_NONPOSITIVE, "the capacity must be positive"); + CASE(CAPACITY_MOD_8, "the capacity must be a multiple of 8"); + CASE(BITRATE_NONPOSITIVE, "the rate must be positive"); + CASE(BITRATE_MOD_8, "the rate must be a multiple of 8"); + CASE(OUTPUT_NONPOSITIVE, "the output size must be positive"); + CASE(STATE_BITRATE_CAPACITY_INCONSISTENCY, "the sum of the rate and capacity must equal" + " the state size (25 times the word size)"); + default: + eprintf("unknown error in algorithm parameters"); + } +# undef CASE + +# define CASE(N, S) case LIBKECCAK_SPEC_ERROR_##N: eprintf("%s", S) + switch (libkeccak_spec_check(&spec)) { + case 0: + break; + CASE(BITRATE_NONPOSITIVE, "the rate size must be positive"); + CASE(BITRATE_MOD_8, "the rate must be a multiple of 8"); + CASE(CAPACITY_NONPOSITIVE, "the capacity must be positive"); + CASE(CAPACITY_MOD_8, "the capacity must be a multiple of 8"); + CASE(OUTPUT_NONPOSITIVE, "the output size must be positive"); + CASE(STATE_TOO_LARGE, "the state size is too large, may not exceed 1600"); + CASE(STATE_MOD_25, "the state size must be a multiple of 25"); + CASE(WORD_NON_2_POTENT, "the word size must be a power of 2"); + CASE(WORD_MOD_8, "the word size must be a multiple of 8"); + default: + eprintf("unknown error in algorithm parameters"); + } +# undef TEST + + if (verbose) { + fprintf(stderr, "rate: %li\n", gspec.bitrate); + fprintf(stderr, "capacity: %li\n", gspec.capacity); + fprintf(stderr, "output size: %li\n", gspec.output); + fprintf(stderr, "state size: %li\n", gspec.state_size); + fprintf(stderr, "word size: %li\n", gspec.word_size); + fprintf(stderr, "squeezes: %li\n", z); + fprintf(stderr, "suffix: %s\n", suffix); + } +#else + (void) verbose; +#endif + + if (*algorithm == LIBHASHSUM_KECCAK && !s && !w) + *algostr = *algostrbuf = fmtalgostr(*algostr, r, c, n, z); + +#ifdef SUPPORT_SHA3 + r = spec.bitrate; + c = spec.capacity; + n = spec.output; +#else + if (w && !s) + s = w * 25; + if (!!r + !!c == 2 && !s) { + n = n ? n : MAX(c * 2, 8); + } else if (!!r + !!c == 1) { + c = c ? c : (s ? s : 1600) - r; + r = r ? r : (s ? s : 1600) - c; + n = n ? n : MAX(c * 2, 8); + } else { + c = (s ? s : 1600) * 9 / 25; + r = (s ? s : 1600) - c; + n = n ? n : MAX(r / 2, 8); + } +#endif + + if (*algorithm == LIBHASHSUM_KECCAK && (s || w)) + *algostr = *algostrbuf = fmtalgostr(*algostr, r, c, n, z); + else if (*algorithm != LIBHASHSUM_KECCAK && n != bits) + *algostr = *algostrbuf = fmtalgostr(*algostr, 0, 0, n, 0); + + return argc; +} |