/* See LICENSE file for copyright and license details. */ #include "common.h" #ifdef SUPPORT_SHA3 #include #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; }