/* 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;
}