aboutsummaryrefslogtreecommitdiffstats
path: root/cmdline_sha3sum.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cmdline_sha3sum.c321
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;
+}