Hello, In the task T6637, adding cSHAKE and KMAC is proposed. I read the patch, while it works somehow, it is not easy to merge it directly.
Thus, I do implement cSHAKE part, with minimum change. Attached is my try. I plan to take the test vectors for cSHAKE from the patch in T6637 and add them. --
>From 883774a0f5b2770bbc1c5c84bea2a403d6d46605 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka <gni...@fsij.org> Date: Tue, 26 Mar 2024 13:39:55 +0900 Subject: [PATCH] md: Add cSHAKE digest algorithm and the implementation. * src/gcrypt.h.in (gcry_ctl_cmds): Add GCRYCTL_MD_CUSTOMIZE. (gcry_md_algos): Add GCRY_MD_CSHAKE128 and GCRY_MD_CSHAKE256. (struct gcry_cshake_customization): New. * cipher/keccak.c (CSHAKE_DELIMITED_SUFFIX): New. (keccak_init): Support GCRY_MD_CSHAKE128 and GCRY_MD_CSHAKE256. (selftests_keccak): Likewise. (cshake_input_n, cshake_input_s, _gcry_cshake_customize): New. (cshake128_init, cshake256_init, cshake_hash_buffers): New. (_gcry_cshake128_hash_buffers, _gcry_cshake256_hash_buffers): New. (_gcry_digest_spec_cshake128, _gcry_digest_spec_cshake256): New. * cipher/md.c (digest_list): Add cSHAKE md_specs. (digest_list_algo301): Likewise. (md_customize): New. (_gcry_md_ctl): Support GCRYCTL_MD_CUSTOMIZE. * src/cipher.h (_gcry_cshake_customize): New. (_gcry_digest_spec_cshake128, _gcry_digest_spec_cshake256): New. * src/fips.c (_gcry_fips_indicator_md): Support GCRY_MD_CSHAKE128 and GCRY_MD_CSHAKE256. * tests/basic.c (check_one_md): Support GCRY_MD_CSHAKE128 and GCRY_MD_CSHAKE256 as xof. (check_one_md_multi): Exclude GCRY_MD_CSHAKE128 and GCRY_MD_CSHAKE256 as xof. * tests/bench-slope.c (hash_bench, kdf_bench): Exclude GCRY_MD_CSHAKE128 and GCRY_MD_CSHAKE256. * tests/benchmark.c (md_bench): Exclude GCRY_MD_CSHAKE128 and GCRY_MD_CSHAKE256. -- Signed-off-by: NIIBE Yutaka <gni...@fsij.org> --- cipher/keccak.c | 168 +++++++++++++++++++++++++++++++++++++++++++- cipher/md.c | 63 ++++++++++++++++- doc/gcrypt.texi | 15 +++- src/cipher.h | 6 ++ src/fips.c | 2 + src/gcrypt.h.in | 15 +++- tests/basic.c | 6 +- tests/bench-slope.c | 11 ++- tests/benchmark.c | 2 + 9 files changed, 279 insertions(+), 9 deletions(-) diff --git a/cipher/keccak.c b/cipher/keccak.c index cc055a1c..aaf83a62 100644 --- a/cipher/keccak.c +++ b/cipher/keccak.c @@ -112,7 +112,7 @@ #define SHA3_DELIMITED_SUFFIX 0x06 #define SHAKE_DELIMITED_SUFFIX 0x1F - +#define CSHAKE_DELIMITED_SUFFIX 0x04 typedef struct { @@ -1025,11 +1025,13 @@ keccak_init (int algo, void *context, unsigned int flags) ctx->blocksize = 576 / 8; ctx->outlen = 512 / 8; break; + case GCRY_MD_CSHAKE128: case GCRY_MD_SHAKE128: ctx->suffix = SHAKE_DELIMITED_SUFFIX; ctx->blocksize = 1344 / 8; ctx->outlen = 256 / 8; break; + case GCRY_MD_CSHAKE256: case GCRY_MD_SHAKE256: ctx->suffix = SHAKE_DELIMITED_SUFFIX; ctx->blocksize = 1088 / 8; @@ -1059,9 +1061,11 @@ keccak_init (int algo, void *context, unsigned int flags) case GCRY_MD_SHA3_512: kimd_func = KMID_FUNCTION_SHA3_512; break; + case GCRY_MD_CSHAKE128: case GCRY_MD_SHAKE128: kimd_func = KMID_FUNCTION_SHAKE128; break; + case GCRY_MD_CSHAKE256: case GCRY_MD_SHAKE256: kimd_func = KMID_FUNCTION_SHAKE256; break; @@ -1423,6 +1427,146 @@ _gcry_shake256_hash_buffers (void *outbuf, size_t nbytes, &_gcry_digest_spec_shake256); } + +static unsigned int +cshake_input_n (KECCAK_CONTEXT *ctx, const void *n, unsigned int n_len) +{ + unsigned char buf[3]; + + buf[0] = 1; + buf[1] = ctx->blocksize; + keccak_write (ctx, buf, 2); + + /* Here, N_LEN must be less than 255 */ + if (n_len < 32) + { + buf[0] = 1; + buf[1] = n_len * 8; + } + else + { + buf[0] = 2; + buf[1] = (n_len * 8) >> 8; + buf[2] = (n_len * 8) & 0xff; + } + + keccak_write (ctx, buf, buf[0] + 1); + keccak_write (ctx, n, n_len); + return 2 + buf[0] + 1 + n_len; +} + +static void +cshake_input_s (KECCAK_CONTEXT *ctx, const void *s, unsigned int s_len, + unsigned int len_written) +{ + unsigned char buf[168]; + unsigned int padlen; + + /* Here, S_LEN must be less than 255 */ + if (s_len < 32) + { + buf[0] = 1; + buf[1] = s_len * 8; + } + else + { + buf[0] = 2; + buf[1] = (s_len * 8) >> 8; + buf[2] = (s_len * 8) & 0xff; + } + + keccak_write (ctx, buf, buf[0] + 1); + keccak_write (ctx, s, s_len); + + len_written += buf[0] + 1 + s_len; + padlen = ctx->blocksize - (len_written % ctx->blocksize); + memset (buf, 0, padlen); + keccak_write (ctx, buf, padlen); +} + +gpg_err_code_t +_gcry_cshake_customize (void *context, struct gcry_cshake_customization *p) +{ + KECCAK_CONTEXT *ctx = (KECCAK_CONTEXT *) context; + unsigned int len_written; + + if (p->n_len >= 255 || p->s_len >= 255) + return GPG_ERR_TOO_LARGE; + + if (p->n_len == 0 && p->s_len == 0) + /* No customization */ + return 0; + + len_written = cshake_input_n (ctx, p->n, p->n_len); + cshake_input_s (ctx, p->s, p->s_len, len_written); + ctx->suffix = CSHAKE_DELIMITED_SUFFIX; + return 0; +} + + +static void +cshake128_init (void *context, unsigned int flags) +{ + keccak_init (GCRY_MD_CSHAKE128, context, flags); +} + +static void +cshake256_init (void *context, unsigned int flags) +{ + keccak_init (GCRY_MD_CSHAKE256, context, flags); +} + +static void +cshake_hash_buffers (const gcry_md_spec_t *spec, void *outbuf, size_t nbytes, + const gcry_buffer_t *iov, int iovcnt) +{ + KECCAK_CONTEXT ctx; + + spec->init (&ctx, 0); + + if (iovcnt < 2) + ; /* No customization, do same as SHAKE does. */ + else + { + if (iov[0].len != 0 || iov[1].len != 0) + { + const void *n = (unsigned char *)iov[0].data + iov[0].off; + size_t n_len = iov[0].len; + const void *s = (unsigned char *)iov[1].data + iov[1].off; + size_t s_len = iov[1].len; + size_t len; + + len = cshake_input_n (&ctx, n, n_len); + cshake_input_s (&ctx, s, s_len, len); + ctx.suffix = CSHAKE_DELIMITED_SUFFIX; + } + iovcnt -= 2; + iov += 2; + } + + for (;iovcnt > 0; iov++, iovcnt--) + keccak_write (&ctx, (const char*)iov[0].data + iov[0].off, iov[0].len); + keccak_final (&ctx); + do_keccak_extract (&ctx, outbuf, nbytes); +} + +static void +_gcry_cshake128_hash_buffers (void *outbuf, size_t nbytes, + const gcry_buffer_t *iov, int iovcnt) +{ + const gcry_md_spec_t *spec = &_gcry_digest_spec_shake128; + + cshake_hash_buffers (spec, outbuf, nbytes, iov, iovcnt); +} + +static void +_gcry_cshake256_hash_buffers (void *outbuf, size_t nbytes, + const gcry_buffer_t *iov, int iovcnt) +{ + const gcry_md_spec_t *spec = &_gcry_digest_spec_shake256; + + cshake_hash_buffers (spec, outbuf, nbytes, iov, iovcnt); +} /* Self-test section. @@ -1505,6 +1649,7 @@ selftests_keccak (int algo, int extended, selftest_report_func_t report) hash_len = 64; break; + case GCRY_MD_CSHAKE128: case GCRY_MD_SHAKE128: short_hash = "\x58\x81\x09\x2d\xd8\x18\xbf\x5c\xf8\xa3\xdd\xb7\x93\xfb\xcb\xa7" @@ -1518,6 +1663,7 @@ selftests_keccak (int algo, int extended, selftest_report_func_t report) hash_len = 32; break; + case GCRY_MD_CSHAKE256: case GCRY_MD_SHAKE256: short_hash = "\x48\x33\x66\x60\x13\x60\xa8\x77\x1c\x68\x63\x08\x0c\xc4\x11\x4d" @@ -1577,7 +1723,9 @@ run_selftests (int algo, int extended, selftest_report_func_t report) case GCRY_MD_SHA3_256: case GCRY_MD_SHA3_384: case GCRY_MD_SHA3_512: + case GCRY_MD_CSHAKE128: case GCRY_MD_SHAKE128: + case GCRY_MD_CSHAKE256: case GCRY_MD_SHAKE256: ec = selftests_keccak (algo, extended, report); break; @@ -1736,3 +1884,21 @@ const gcry_md_spec_t _gcry_digest_spec_shake256 = sizeof (KECCAK_CONTEXT), run_selftests }; +const gcry_md_spec_t _gcry_digest_spec_cshake128 = + { + GCRY_MD_CSHAKE128, {0, 1}, + "CSHAKE128", NULL, 0, NULL, 32, + cshake128_init, keccak_write, keccak_final, keccak_shake_read, + keccak_extract, _gcry_cshake128_hash_buffers, + sizeof (KECCAK_CONTEXT), + run_selftests + }; +const gcry_md_spec_t _gcry_digest_spec_cshake256 = + { + GCRY_MD_CSHAKE256, {0, 1}, + "CSHAKE256", NULL, 0, NULL, 64, + cshake256_init, keccak_write, keccak_final, keccak_shake_read, + keccak_extract, _gcry_cshake256_hash_buffers, + sizeof (KECCAK_CONTEXT), + run_selftests + }; diff --git a/cipher/md.c b/cipher/md.c index ee910689..e50bbc2f 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -58,6 +58,8 @@ static const gcry_md_spec_t * const digest_list[] = &_gcry_digest_spec_sha3_512, &_gcry_digest_spec_shake128, &_gcry_digest_spec_shake256, + &_gcry_digest_spec_cshake128, + &_gcry_digest_spec_cshake256, #endif #if USE_GOST_R_3411_94 &_gcry_digest_spec_gost3411_94, @@ -240,7 +242,14 @@ static const gcry_md_spec_t * const digest_list_algo301[] = #endif #if USE_SHA512 &_gcry_digest_spec_sha512_256, - &_gcry_digest_spec_sha512_224 + &_gcry_digest_spec_sha512_224, +#else + NULL, + NULL, +#endif +#if USE_SHA3 + &_gcry_digest_spec_cshake128, + &_gcry_digest_spec_cshake256, #else NULL, NULL @@ -996,6 +1005,55 @@ prepare_macpads (gcry_md_hd_t a, const unsigned char *key, size_t keylen) } +static gcry_err_code_t +md_customize (gcry_md_hd_t h, void *buffer, size_t buflen) +{ + gcry_err_code_t rc = 0; + GcryDigestEntry *r; + int algo_had_customize = 0; + + if (!h->ctx->list) + return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ + + for (r = h->ctx->list; r; r = r->next) + { + switch (r->spec->algo) + { + case GCRY_MD_CSHAKE128: + case GCRY_MD_CSHAKE256: + algo_had_customize = 1; + if (buflen != sizeof (struct gcry_cshake_customization)) + rc = GPG_ERR_INV_ARG; + else + rc = _gcry_cshake_customize (r->context, buffer); + break; + default: + rc = GPG_ERR_DIGEST_ALGO; + break; + } + + if (rc) + break; + } + + if (rc && !algo_had_customize) + { + /* None of algorithms had customize implementation, so contexts were not + * modified. Just return error. */ + return rc; + } + else if (rc && algo_had_customize) + { + /* Some of the contexts have been modified, but got error. Reset + * all contexts. */ + _gcry_md_reset (h); + return rc; + } + + return 0; +} + + gcry_err_code_t _gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) { @@ -1014,6 +1072,9 @@ _gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) case GCRYCTL_STOP_DUMP: md_stop_debug ( hd ); break; + case GCRYCTL_MD_CUSTOMIZE: + rc = md_customize (hd, buffer, buflen); + break; default: rc = GPG_ERR_INV_OP; } diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 92491f4a..c10c0b47 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -3606,7 +3606,7 @@ are also supported. @c begin table of hash algorithms @cindex SHA-1 @cindex SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 -@cindex SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 +@cindex SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256, cSHAKE128, cSHAKE256 @cindex RIPE-MD-160 @cindex MD2, MD4, MD5 @cindex TIGER, TIGER1, TIGER2 @@ -3716,6 +3716,19 @@ This is the SHAKE256 extendable-output function (XOF) algorithm with 256 bit security strength. See FIPS 202 for the specification. +@item GCRY_MD_CSHAKE128 +This is the cSHAKE128 extendable-output function (XOF) algorithm with +128 bit security strength defined in NIST SP 800-185. cSHAKE takes +two optional additional inputs N and S, which can be set by using +@code{gcry_md_ctl} with the control commands @code{GCRYCTL_MD_CUSTOMISE}, +and the argument @code{struct gcry_cshake_customization}. The lengths +of N or S is limited to 255 bytes. + +@item GCRY_MD_CSHAKE256 +This is the cSHAKE256 extendable-output function (XOF) algorithm with 256 bit +security strength defined in NIST SP 800-185. Regarding the usage of the +optional additional inputs N and S, see the above description of cSHAKE128. + @item GCRY_MD_CRC32 This is the ISO 3309 and ITU-T V.42 cyclic redundancy check. It yields an output of 4 bytes. Note that this is not a hash algorithm in the diff --git a/src/cipher.h b/src/cipher.h index ae6337c2..0a2551fe 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -142,6 +142,10 @@ void _gcry_register_pk_ecc_progress (gcry_handler_progress_t cbc, void _gcry_register_primegen_progress (gcry_handler_progress_t cb, void *cb_data); +/*-- keccak.c --*/ +gpg_err_code_t _gcry_cshake_customize (void *context, + struct gcry_cshake_customization *p); + /*-- pubkey.c --*/ /* Declarations for the cipher specifications. */ @@ -200,6 +204,8 @@ extern const gcry_md_spec_t _gcry_digest_spec_sha3_512; extern const gcry_md_spec_t _gcry_digest_spec_sha3_384; extern const gcry_md_spec_t _gcry_digest_spec_shake128; extern const gcry_md_spec_t _gcry_digest_spec_shake256; +extern const gcry_md_spec_t _gcry_digest_spec_cshake128; +extern const gcry_md_spec_t _gcry_digest_spec_cshake256; extern const gcry_md_spec_t _gcry_digest_spec_tiger; extern const gcry_md_spec_t _gcry_digest_spec_tiger1; extern const gcry_md_spec_t _gcry_digest_spec_tiger2; diff --git a/src/fips.c b/src/fips.c index 574776ac..cf91baa8 100644 --- a/src/fips.c +++ b/src/fips.c @@ -422,6 +422,8 @@ _gcry_fips_indicator_md (va_list arg_ptr) case GCRY_MD_SHA3_512: case GCRY_MD_SHAKE128: case GCRY_MD_SHAKE256: + case GCRY_MD_CSHAKE128: + case GCRY_MD_CSHAKE256: return GPG_ERR_NO_ERROR; default: return GPG_ERR_NOT_SUPPORTED; diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 441e8d78..a9d6b87f 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -333,7 +333,8 @@ enum gcry_ctl_cmds GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION = 84, GCRYCTL_FIPS_SERVICE_INDICATOR_MAC = 85, GCRYCTL_FIPS_SERVICE_INDICATOR_MD = 86, - GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS = 87 + GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS = 87, + GCRYCTL_MD_CUSTOMIZE = 88 }; /* Perform various operations defined by CMD. */ @@ -1305,7 +1306,9 @@ enum gcry_md_algos GCRY_MD_BLAKE2S_128 = 325, GCRY_MD_SM3 = 326, GCRY_MD_SHA512_256 = 327, - GCRY_MD_SHA512_224 = 328 + GCRY_MD_SHA512_224 = 328, + GCRY_MD_CSHAKE128 = 329, + GCRY_MD_CSHAKE256 = 330 }; /* Flags used with the open function. */ @@ -1461,6 +1464,14 @@ void gcry_md_debug (gcry_md_hd_t hd, const char *suffix); #define gcry_md_get_asnoid(a,b,n) \ gcry_md_algo_info((a), GCRYCTL_GET_ASNOID, (b), (n)) +struct gcry_cshake_customization +{ + const void *n; + unsigned int n_len; + const void *s; + unsigned int s_len; +}; + /********************************************** diff --git a/tests/basic.c b/tests/basic.c index 8c4e50f4..ebe6f6d0 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -13605,7 +13605,8 @@ check_one_md (int algo, const char *data, int len, const char *expect, int elen, mdlen = gcry_md_get_algo_dlen (algo); if (elen != 0 && mdlen != elen - && (algo == GCRY_MD_SHAKE128 || algo == GCRY_MD_SHAKE256)) + && (algo == GCRY_MD_SHAKE128 || algo == GCRY_MD_SHAKE256 + || algo == GCRY_MD_CSHAKE128 || algo == GCRY_MD_CSHAKE256)) { xof = 1; } @@ -13959,7 +13960,8 @@ check_one_md_multi (int algo, const char *data, int len, const char *expect, } if (elen != 0 && elen != mdlen - && (algo == GCRY_MD_SHAKE128 || algo == GCRY_MD_SHAKE256)) + && (algo == GCRY_MD_SHAKE128 || algo == GCRY_MD_SHAKE256 + || algo == GCRY_MD_CSHAKE128 || algo == GCRY_MD_CSHAKE256)) return; if (*data == '!' && !data[1]) diff --git a/tests/bench-slope.c b/tests/bench-slope.c index 6b3a6ccd..4b14541b 100644 --- a/tests/bench-slope.c +++ b/tests/bench-slope.c @@ -2000,7 +2000,9 @@ hash_bench (char **argv, int argc) else { for (i = 1; i < 400; i++) - if (!gcry_md_test_algo (i)) + if (i == GCRY_MD_CSHAKE128 || i == GCRY_MD_CSHAKE256) + ; /* Skip the bench. */ + else if (!gcry_md_test_algo (i)) _hash_bench (i); } @@ -2295,6 +2297,9 @@ kdf_bench (char **argv, int argc) { for (j = 1; j < 400; j++) { + if (i == GCRY_MD_CSHAKE128 || i == GCRY_MD_CSHAKE256) + continue; /* Skip the bench. */ + if (gcry_md_test_algo (j)) continue; @@ -2309,7 +2314,9 @@ kdf_bench (char **argv, int argc) else { for (i = 1; i < 400; i++) - if (!gcry_md_test_algo (i)) + if (i == GCRY_MD_CSHAKE128 || i == GCRY_MD_CSHAKE256) + ; /* Skip the bench. */ + else if (!gcry_md_test_algo (i)) kdf_bench_one (GCRY_KDF_PBKDF2, i); } diff --git a/tests/benchmark.c b/tests/benchmark.c index 57c2428a..48025bbc 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -489,6 +489,8 @@ md_bench ( const char *algoname ) for (i=1; i < 400; i++) if (in_fips_mode && i == GCRY_MD_MD5) ; /* Don't use MD5 in fips mode. */ + else if (i == GCRY_MD_CSHAKE128 || i == GCRY_MD_CSHAKE256) + ; /* Skip. */ else if ( !gcry_md_test_algo (i) ) md_bench (gcry_md_algo_name (i)); return; -- 2.39.2
_______________________________________________ Gcrypt-devel mailing list Gcrypt-devel@gnupg.org https://lists.gnupg.org/mailman/listinfo/gcrypt-devel