aboutsummaryrefslogblamecommitdiffstats
path: root/cmdline_sha3sum.c
blob: 8fc33fd22a19279c57da41011de9023f721226af (plain) (tree)
































































































































































































































































































































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