From jussi.kivilinna at iki.fi Thu Jun 1 20:25:39 2023 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Thu, 1 Jun 2023 21:25:39 +0300 Subject: [PATCH] rijndael-aesni: use inline checksumming for OCB decryption In-Reply-To: <918b7158-7385-c845-c102-ffca049d8f41@iki.fi> References: <20230528145355.532424-1-jussi.kivilinna@iki.fi> <87ilcajei9.fsf@wheatstone.g10code.de> <918b7158-7385-c845-c102-ffca049d8f41@iki.fi> Message-ID: <94c7c640-0a54-0417-2a19-5b286658624b@iki.fi> On 31.5.2023 7.48, Jussi Kivilinna wrote: > On 30.5.2023 13.32, Werner Koch via Gcrypt-devel wrote: >> On Sun, 28 May 2023 17:53, Jussi Kivilinna said: >> >>> Inline checksumming is far faster on Ryzen processors on i386 >>> builds than two-pass checksumming. >> >> That is indeed a large performance boost.? Did you had a chance to >> benchmark it on some common Intel CPU? >> > > I tested now with Intel tigerlake, performance dropped by 9% which is > unexpectedly large change. I'll try few different things to see if > I can avoid such drop. Performance problem I'm seen is limited to Zen4 and only 32-bit execution mode. Running same code in 64-bit mode does not suffer from this problem. Seems to be somehow related to mixed XMM/YMM register usage and vzeroupper instruction not work as expected. For example, if I disable 8-blocks AES-OCB-enc loop and add following instructions at the end of 4-blocks loop: "vpcmpeqd %%ymm0, %%ymm0, %%ymm0\n\t" "vzeroupper\n\t" With these instructions, I see approx two times slower performance in 32bit-mode (0.851 cycles/byte vs 0.411 c/B). In 64bit-mode above instructions slow execution only about 1% (0.418 c/B vs 0.414 c/B). So, I won't apply this patch after all. -Jussi > > -Jussi > >> >> Shalom-Salam, >> >> ??? Werner >> >> >> _______________________________________________ >> Gcrypt-devel mailing list >> Gcrypt-devel at gnupg.org >> https://lists.gnupg.org/mailman/listinfo/gcrypt-devel > > > _______________________________________________ > Gcrypt-devel mailing list > Gcrypt-devel at gnupg.org > https://lists.gnupg.org/mailman/listinfo/gcrypt-devel From guidovranken at gmail.com Fri Jun 2 03:20:39 2023 From: guidovranken at gmail.com (Guido Vranken) Date: Fri, 2 Jun 2023 03:20:39 +0200 Subject: Modular add/sub/mul incorrect result if result and modulus pointer are equal Message-ID: In the following program, the results of addm, subm or mulm are all zero, but should be 6, 5 and 1, respectively. #include #define CF_CHECK_EQ(expr, res) if ( (expr) != (res) ) { goto end; } int main(void) { gcry_mpi_t A; gcry_mpi_t B; gcry_mpi_t C; gcry_error_t err; char *buf; CF_CHECK_EQ(err = gcry_mpi_scan(&A, GCRYMPI_FMT_HEX, "2", 0, NULL), 0); CF_CHECK_EQ(err = gcry_mpi_scan(&B, GCRYMPI_FMT_HEX, "4", 0, NULL), 0); CF_CHECK_EQ(err = gcry_mpi_scan(&C, GCRYMPI_FMT_HEX, "7", 0, NULL), 0); gcry_mpi_addm(C, A, B, C); //gcry_mpi_subm(C, A, B, C); //gcry_mpi_mulm(C, A, B, C); CF_CHECK_EQ(err = gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char**)&buf, NULL, C), 0); printf("%s\n", buf); gcry_mpi_release(A); gcry_mpi_release(B); gcry_mpi_release(C); gcry_free(buf); end: return 0; } -------------- next part -------------- An HTML attachment was scrubbed... URL: From wk at gnupg.org Fri Jun 2 11:27:46 2023 From: wk at gnupg.org (Werner Koch) Date: Fri, 02 Jun 2023 11:27:46 +0200 Subject: Modular add/sub/mul incorrect result if result and modulus pointer are equal In-Reply-To: (Guido Vranken via Gcrypt-devel's message of "Fri, 2 Jun 2023 03:20:39 +0200") References: Message-ID: <87wn0mfc31.fsf@wheatstone.g10code.de> On Fri, 2 Jun 2023 03:20, Guido Vranken said: > In the following program, the results of addm, subm or mulm are all zero, > but should be 6, 5 and 1, respectively. I modified the included mpicalc program (patch against 1.10 attached) to allow for addm and subm but can't replicate your findings.: $ mpicalc 2 4 7 M+pc 06 2 4 7 M-pc 05 2 4 7 mpc 01 I have not checked your code, though. Shalom-Salam, Werner -- The pioneers of a warless world are the youth that refuse military service. - A. Einstein -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-mpicalc-Allow-for-addm-and-subm.patch Type: text/x-diff Size: 2860 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: openpgp-digital-signature.asc Type: application/pgp-signature Size: 227 bytes Desc: not available URL: From jussi.kivilinna at iki.fi Fri Jun 2 18:43:26 2023 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Fri, 2 Jun 2023 19:43:26 +0300 Subject: Modular add/sub/mul incorrect result if result and modulus pointer are equal In-Reply-To: <87wn0mfc31.fsf@wheatstone.g10code.de> References: <87wn0mfc31.fsf@wheatstone.g10code.de> Message-ID: On 2.6.2023 12.27, Werner Koch via Gcrypt-devel wrote: > On Fri, 2 Jun 2023 03:20, Guido Vranken said: >> In the following program, the results of addm, subm or mulm are all zero, >> but should be 6, 5 and 1, respectively. > > I modified the included mpicalc program (patch against 1.10 attached) to > allow for addm and subm but can't replicate your findings.: > > $ mpicalc > 2 > 4 > 7 > M+pc > 06 > 2 > 4 > 7 > M-pc > 05 > 2 > 4 > 7 > mpc > 01 > > I have not checked your code, though. Below is code for mpi_addm. If W and M are the same (as is in Guido's example), then it looks that W and M gets replaced by mpi_add result. After that mpi_mod gives zero as result (have not tested, just inspecting code). void _gcry_mpi_addm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m) { mpi_add (w, u, v); mpi_mod (w, w, m); } -Jussi > > > Shalom-Salam, > > Werner > > > _______________________________________________ > Gcrypt-devel mailing list > Gcrypt-devel at gnupg.org > https://lists.gnupg.org/mailman/listinfo/gcrypt-devel From jussi.kivilinna at iki.fi Sat Jun 3 12:23:26 2023 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sat, 3 Jun 2023 13:23:26 +0300 Subject: [PATCH] addm/subm/mulm: fix case when destination is same MPI as divider In-Reply-To: References: Message-ID: <20230603102326.226265-1-jussi.kivilinna@iki.fi> * mpi/mpi-add.c (_gcry_mpi_addm, _gcry_mpi_subm): Take copy of M when W and M are the same MPI. * mpi/mpi-mul.c (_gcry_mpi_mulm): Likewise. * tests/mpitests.c (test_addm_subm_mulm): New. (main): Run addm/subm/mulm test. -- Reported-by: Guido Vranken Signed-off-by: Jussi Kivilinna --- mpi/mpi-add.c | 22 ++++++++++++++++++++ mpi/mpi-mul.c | 11 ++++++++++ tests/mpitests.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/mpi/mpi-add.c b/mpi/mpi-add.c index 41dc3900..51dc71b7 100644 --- a/mpi/mpi-add.c +++ b/mpi/mpi-add.c @@ -227,13 +227,35 @@ _gcry_mpi_sub(gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v) void _gcry_mpi_addm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m) { + gcry_mpi_t temp_m = NULL; + + if (w == m) + { + temp_m = mpi_copy (m); + m = temp_m; + } + mpi_add (w, u, v); mpi_mod (w, w, m); + + if (temp_m) + mpi_free(temp_m); } void _gcry_mpi_subm( gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m) { + gcry_mpi_t temp_m = NULL; + + if (w == m) + { + temp_m = mpi_copy (m); + m = temp_m; + } + mpi_sub (w, u, v); mpi_mod (w, w, m); + + if (temp_m) + mpi_free(temp_m); } diff --git a/mpi/mpi-mul.c b/mpi/mpi-mul.c index 60f1ca48..e8e57475 100644 --- a/mpi/mpi-mul.c +++ b/mpi/mpi-mul.c @@ -207,6 +207,17 @@ _gcry_mpi_mul (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v) void _gcry_mpi_mulm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m) { + gcry_mpi_t temp_m = NULL; + + if (w == m) + { + temp_m = mpi_copy (m); + m = temp_m; + } + mpi_mul (w, u, v); _gcry_mpi_tdiv_r (w, w, m); + + if (temp_m) + mpi_free(temp_m); } diff --git a/tests/mpitests.c b/tests/mpitests.c index 48ea18b2..1203acdd 100644 --- a/tests/mpitests.c +++ b/tests/mpitests.c @@ -687,6 +687,58 @@ test_powm (void) } +/* What we test here is that we don't overwrite our divider and that + using the same mpi for divider and result works. */ +static int +test_addm_subm_mulm (void) +{ + int i; + + for (i = 0; i < 3; i++) + { + unsigned int expect; + const char *func; + gcry_mpi_t A; + gcry_mpi_t B; + gcry_mpi_t C; + + A = gcry_mpi_set_ui (NULL, 2); + B = gcry_mpi_set_ui (NULL, 4); + C = gcry_mpi_set_ui (NULL, 7); + + if (i == 0) + { + func = "mpi_addm"; + expect = 6; + gcry_mpi_addm(C, A, B, C); + } + else if (i == 1) + { + func = "mpi_subm"; + expect = 5; + gcry_mpi_subm(C, A, B, C); + } + else if (i == 2) + { + func = "mpi_mulm"; + expect = 1; + gcry_mpi_mulm(C, A, B, C); + } + + if (gcry_mpi_is_neg (C) || gcry_mpi_cmp_ui (C, expect)) + { + die ("test_addm_subm_mulm failed for %s at %d\n", func, __LINE__); + } + + gcry_mpi_release(A); + gcry_mpi_release(B); + gcry_mpi_release(C); + } + + return 1; +} + + int main (int argc, char* argv[]) { @@ -710,6 +762,7 @@ main (int argc, char* argv[]) test_sub (); test_mul (); test_powm (); + test_addm_subm_mulm (); return !!error_count; } -- 2.39.2 From gniibe at fsij.org Tue Jun 20 02:43:31 2023 From: gniibe at fsij.org (NIIBE Yutaka) Date: Tue, 20 Jun 2023 09:43:31 +0900 Subject: Adding the READ method for SHAKE Message-ID: <87h6r3q7yk.fsf@akagi.fsij.org> Hello, I'd like to propose a change for the SHAKE implementation. This comes in the context of a bug in gcry_pk_hash_sign: https://dev.gnupg.org/T6539 I learned that there is a use case of SHAKE in CMS, specified in RFC 8802. Use of the SHAKE One-Way Hash Functions in the Cryptographic Message Syntax (CMS): https://www.rfc-editor.org/rfc/rfc8702.html In RFC 8802, SHAKE128 is used with 32-byte output, and SHAKE256 is used with 64-byte output. I think that: when a digest function is used for signing, fixed size makes sense, as the matter is the strength of the hash function. Considering this use case for signing, I'd like to add the READ method and the definition of length to the SHAKE digest functions. Attached is the change. How do you think? ========================== diff --git a/cipher/keccak.c b/cipher/keccak.c index 22c40302..76e08cb5 100644 --- a/cipher/keccak.c +++ b/cipher/keccak.c @@ -1630,8 +1630,8 @@ const gcry_md_spec_t _gcry_digest_spec_sha3_512 = const gcry_md_spec_t _gcry_digest_spec_shake128 = { GCRY_MD_SHAKE128, {0, 1}, - "SHAKE128", shake128_asn, DIM (shake128_asn), oid_spec_shake128, 0, - shake128_init, keccak_write, keccak_final, NULL, keccak_extract, + "SHAKE128", shake128_asn, DIM (shake128_asn), oid_spec_shake128, 32, + shake128_init, keccak_write, keccak_final, keccak_read, keccak_extract, _gcry_shake128_hash_buffers, sizeof (KECCAK_CONTEXT), run_selftests @@ -1639,8 +1639,8 @@ const gcry_md_spec_t _gcry_digest_spec_shake128 = const gcry_md_spec_t _gcry_digest_spec_shake256 = { GCRY_MD_SHAKE256, {0, 1}, - "SHAKE256", shake256_asn, DIM (shake256_asn), oid_spec_shake256, 0, - shake256_init, keccak_write, keccak_final, NULL, keccak_extract, + "SHAKE256", shake256_asn, DIM (shake256_asn), oid_spec_shake256, 64, + shake256_init, keccak_write, keccak_final, keccak_read, keccak_extract, _gcry_shake256_hash_buffers, sizeof (KECCAK_CONTEXT), run_selftests -- From jussi.kivilinna at iki.fi Thu Jun 22 08:00:37 2023 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Thu, 22 Jun 2023 09:00:37 +0300 Subject: Adding the READ method for SHAKE In-Reply-To: <87h6r3q7yk.fsf@akagi.fsij.org> References: <87h6r3q7yk.fsf@akagi.fsij.org> Message-ID: <1aae30e9-2198-b03a-d04c-ac675a4c4908@iki.fi> Hello, On 20.6.2023 3.43, NIIBE Yutaka wrote: > Hello, > > I'd like to propose a change for the SHAKE implementation. > > This comes in the context of a bug in gcry_pk_hash_sign: > > https://dev.gnupg.org/T6539 > > I learned that there is a use case of SHAKE in CMS, specified in RFC > 8802. > > Use of the SHAKE One-Way Hash Functions in the Cryptographic Message > Syntax (CMS): https://www.rfc-editor.org/rfc/rfc8702.html > > In RFC 8802, SHAKE128 is used with 32-byte output, and SHAKE256 is used > with 64-byte output. > > I think that: when a digest function is used for signing, fixed size > makes sense, as the matter is the strength of the hash function. > > Considering this use case for signing, I'd like to add the READ method > and the definition of length to the SHAKE digest functions. Attached is > the change. > > How do you think? I think this is good change. For example, Crypto++ uses same digest lengths as this change... 32B for SHAKE128 and 64B for SHAKE256. One thing to notice is that `keccak_final()` prepares `keccak_read()` output only for SHA3 functions (see `if (suffix == SHA3_DELIMITED_SUFFIX)`). Not sure how `keccak_read()` should work for SHAKE. Simultaneous use of `md_extract` and `md_read` on same SHAKE digest object probably does not make much sense and maybe those should block another after either one is used first time. So could add some new flags to KECCAK_CONTEXT... `shake_in_read_mode` and `skake_in_extract_mode` etc. So, in `keccak_read()` we'd have something like: static byte * keccak_read (void *context) { KECCAK_CONTEXT *ctx = (KECCAK_CONTEXT *) context; KECCAK_STATE *hd = &ctx->state; if (ctx->suffix == SHAKE_DELIMITED_SUFFIX) { if (ctx->skake_in_extract_mode) { /* Already in extract mode? Invalid use... should/can return NULL? */ return NULL; } if (!ctx->skake_in_read_mode) { ctx->skake_in_read_mode = 1; #ifdef USE_S390X_CRYPTO if (ctx->kimd_func) { /* TODO: need to check if 'hd' can be direct output here: */ keccak_extract_s390x (context, (void *)hd, ); return (byte *)&hd->u; } #endif /* Switch to the squeezing phase. */ burn = ctx->ops->permute(hd); /* Squeeze out the SHAKE digest. */ nburn = ctx->ops->extract(hd, 0, (void *)hd, ); burn = nburn > burn ? nburn : burn; if (burn) _gcry_burn_stack (burn); } } return (byte *)&hd->u; } `keccak_extract` would have new checks: if (ctx->skake_in_read_mode) return ; /* Need to add return type for keccak_extract. */ if (!ctx->shake_in_extract_mode) ctx->shake_in_extract_mode = 1; I can take deeper look into this in few days. -Jussi > > ========================== > diff --git a/cipher/keccak.c b/cipher/keccak.c > index 22c40302..76e08cb5 100644 > --- a/cipher/keccak.c > +++ b/cipher/keccak.c > @@ -1630,8 +1630,8 @@ const gcry_md_spec_t _gcry_digest_spec_sha3_512 = > const gcry_md_spec_t _gcry_digest_spec_shake128 = > { > GCRY_MD_SHAKE128, {0, 1}, > - "SHAKE128", shake128_asn, DIM (shake128_asn), oid_spec_shake128, 0, > - shake128_init, keccak_write, keccak_final, NULL, keccak_extract, > + "SHAKE128", shake128_asn, DIM (shake128_asn), oid_spec_shake128, 32, > + shake128_init, keccak_write, keccak_final, keccak_read, keccak_extract, > _gcry_shake128_hash_buffers, > sizeof (KECCAK_CONTEXT), > run_selftests > @@ -1639,8 +1639,8 @@ const gcry_md_spec_t _gcry_digest_spec_shake128 = > const gcry_md_spec_t _gcry_digest_spec_shake256 = > { > GCRY_MD_SHAKE256, {0, 1}, > - "SHAKE256", shake256_asn, DIM (shake256_asn), oid_spec_shake256, 0, > - shake256_init, keccak_write, keccak_final, NULL, keccak_extract, > + "SHAKE256", shake256_asn, DIM (shake256_asn), oid_spec_shake256, 64, > + shake256_init, keccak_write, keccak_final, keccak_read, keccak_extract, > _gcry_shake256_hash_buffers, > sizeof (KECCAK_CONTEXT), > run_selftests From gniibe at fsij.org Fri Jun 23 02:31:02 2023 From: gniibe at fsij.org (NIIBE Yutaka) Date: Fri, 23 Jun 2023 09:31:02 +0900 Subject: Adding the READ method for SHAKE In-Reply-To: <87h6r3q7yk.fsf@akagi.fsij.org> References: <87h6r3q7yk.fsf@akagi.fsij.org> Message-ID: <87h6qzt3y1.fsf@akagi.fsij.org> Hello, NIIBE Yutaka wrote: > I learned that there is a use case of SHAKE in CMS, specified in RFC > 8802. > > Use of the SHAKE One-Way Hash Functions in the Cryptographic Message > Syntax (CMS): https://www.rfc-editor.org/rfc/rfc8702.html > > In RFC 8802, SHAKE128 is used with 32-byte output, and SHAKE256 is used > with 64-byte output. I should have addressed this RFC, too: RFC 8692 Internet X.509 Public Key Infrastructure: Additional Algorithm Identifiers for RSASSA-PSS and ECDSA Using SHAKEs https://www.rfc-editor.org/rfc/rfc8692.html It's same for ECDSA. It's same for RSASSA-PSS hash function. It uses SHAKE as fixed size output. In RSASSA-PSS, for the use in MGF1 mask generation function, when SHAKE is used, it's variable length version of SHAKE (depends on the size of RSA modulus). Ah, we need to modify the function mgf1 in rsa-common.c to support SHAKE. I will do that, at first. -- From jussi.kivilinna at iki.fi Sun Jun 25 20:46:23 2023 From: jussi.kivilinna at iki.fi (Jussi Kivilinna) Date: Sun, 25 Jun 2023 21:46:23 +0300 Subject: [PATCH] keccak: add md_read support for SHAKE algorithms Message-ID: <20230625184623.2235050-1-jussi.kivilinna@iki.fi> * cipher/hash-common.c (_gcry_hash_selftest_check_one): Adjust for SHAKE algorithms now returning non-zero for digest length. * cipher/keccak.c (KECCAK_CONTEXT_S): Add 'shake_in_extract_mode' and 'shake_in_read_mode' flags. (keccak_init): Initialize new context fields; set output length for SHAKE algorithms. (keccak_extract): Rename to ... (do_keccak_extract): this and add return value. (keccak_extract): New with 'shake_in_???_mode' checks & setup. (keccak_shake_read): New. (_gcry_sha3_hash_buffers): Adjust for 'spec->mdlen' not being zero for SHAKE algorithms, instead check 'suffix' for type. (_gcry_digest_spec_shake128): Set mdlen to 32 bytes; Set read function. (_gcry_digest_spec_shake256): Set mdlen to 64 bytes; Set read function. * cipher/md.c (md_extract): Pass return value from algo extract function. (_gcry_md_hash_buffers_extract): Adjust for 'spec->mdlen' not being zero for SHAKE algorithms. * src/cipher-proto.h (gcry_md_extract_t): Change return type from 'void' to 'gpg_err_code_t'. * tests/basic.c (check_one_md, check_one_md_multi): Adjust for 'gcry_md_get_algo_dlen()' not being zero for SHAKE algorithms. (check_digests): Add md_read interface test-vectors for SHAKE128 and SHAKE256. -- GnuPG-bug-id: 6539 Signed-off-by: Jussi Kivilinna --- cipher/hash-common.c | 10 +++--- cipher/keccak.c | 76 +++++++++++++++++++++++++++++++++++++------- cipher/md.c | 18 ++++++----- src/cipher-proto.h | 3 +- tests/basic.c | 44 +++++++++++++++---------- 5 files changed, 108 insertions(+), 43 deletions(-) diff --git a/cipher/hash-common.c b/cipher/hash-common.c index ed2d7cac..deff40d7 100644 --- a/cipher/hash-common.c +++ b/cipher/hash-common.c @@ -51,12 +51,10 @@ _gcry_hash_selftest_check_one (int algo, gcry_md_hd_t hd; unsigned char *digest; char aaa[1000]; - int xof = 0; + int expect_xof = 0; - if (_gcry_md_get_algo_dlen (algo) == 0) - xof = 1; - else if (_gcry_md_get_algo_dlen (algo) != expectlen) - return "digest size does not match expected size"; + if (_gcry_md_get_algo_dlen (algo) != expectlen) + expect_xof = 1; err = _gcry_md_open (&hd, algo, 0); if (err) @@ -85,7 +83,7 @@ _gcry_hash_selftest_check_one (int algo, if (!result) { - if (!xof) + if (!expect_xof) { digest = _gcry_md_read (hd, algo); diff --git a/cipher/keccak.c b/cipher/keccak.c index 22c40302..9883af4d 100644 --- a/cipher/keccak.c +++ b/cipher/keccak.c @@ -143,7 +143,9 @@ typedef struct KECCAK_CONTEXT_S unsigned int outlen; unsigned int blocksize; unsigned int count; - unsigned int suffix; + unsigned int suffix:8; + unsigned int shake_in_extract_mode:1; + unsigned int shake_in_read_mode:1; const keccak_ops_t *ops; #ifdef USE_S390X_CRYPTO unsigned int kimd_func; @@ -966,6 +968,8 @@ keccak_init (int algo, void *context, unsigned int flags) memset (hd, 0, sizeof *hd); ctx->count = 0; + ctx->shake_in_extract_mode = 0; + ctx->shake_in_read_mode = 0; /* Select generic implementation. */ #ifdef USE_64BIT @@ -1024,12 +1028,12 @@ keccak_init (int algo, void *context, unsigned int flags) case GCRY_MD_SHAKE128: ctx->suffix = SHAKE_DELIMITED_SUFFIX; ctx->blocksize = 1344 / 8; - ctx->outlen = 0; + ctx->outlen = 256 / 8; break; case GCRY_MD_SHAKE256: ctx->suffix = SHAKE_DELIMITED_SUFFIX; ctx->blocksize = 1088 / 8; - ctx->outlen = 0; + ctx->outlen = 512 / 8; break; default: BUG(); @@ -1181,8 +1185,8 @@ keccak_read (void *context) } -static void -keccak_extract (void *context, void *out, size_t outlen) +static gcry_err_code_t +do_keccak_extract (void *context, void *out, size_t outlen) { KECCAK_CONTEXT *ctx = context; KECCAK_STATE *hd = &ctx->state; @@ -1199,7 +1203,7 @@ keccak_extract (void *context, void *out, size_t outlen) if (ctx->kimd_func) { keccak_extract_s390x (context, out, outlen); - return; + return 0; } #endif @@ -1304,6 +1308,52 @@ keccak_extract (void *context, void *out, size_t outlen) if (burn) _gcry_burn_stack (burn); + + return 0; +} + + +static gcry_err_code_t +keccak_extract (void *context, void *out, size_t outlen) +{ + KECCAK_CONTEXT *ctx = context; + + if (ctx->shake_in_read_mode) + return GPG_ERR_INV_STATE; + if (!ctx->shake_in_extract_mode) + ctx->shake_in_extract_mode = 1; + + return do_keccak_extract (context, out, outlen); +} + + +static byte * +keccak_shake_read (void *context) +{ + KECCAK_CONTEXT *ctx = (KECCAK_CONTEXT *) context; + KECCAK_STATE *hd = &ctx->state; + + if (ctx->shake_in_extract_mode) + { + /* Already in extract mode. */ + return NULL; + } + + if (!ctx->shake_in_read_mode) + { + byte tmpbuf[64]; + + gcry_assert(sizeof(tmpbuf) >= ctx->outlen); + + ctx->shake_in_read_mode = 1; + + do_keccak_extract (context, tmpbuf, ctx->outlen); + buf_cpy (&hd->u, tmpbuf, ctx->outlen); + + wipememory(tmpbuf, sizeof(tmpbuf)); + } + + return (byte *)&hd->u; } @@ -1318,10 +1368,10 @@ _gcry_sha3_hash_buffers (void *outbuf, size_t nbytes, const gcry_buffer_t *iov, for (;iovcnt > 0; iov++, iovcnt--) keccak_write (&hd, (const char*)iov[0].data + iov[0].off, iov[0].len); keccak_final (&hd); - if (spec->mdlen > 0) + if (hd.suffix == SHA3_DELIMITED_SUFFIX) memcpy (outbuf, keccak_read (&hd), spec->mdlen); else - keccak_extract (&hd, outbuf, nbytes); + do_keccak_extract (&hd, outbuf, nbytes); } @@ -1630,8 +1680,9 @@ const gcry_md_spec_t _gcry_digest_spec_sha3_512 = const gcry_md_spec_t _gcry_digest_spec_shake128 = { GCRY_MD_SHAKE128, {0, 1}, - "SHAKE128", shake128_asn, DIM (shake128_asn), oid_spec_shake128, 0, - shake128_init, keccak_write, keccak_final, NULL, keccak_extract, + "SHAKE128", shake128_asn, DIM (shake128_asn), oid_spec_shake128, 32, + shake128_init, keccak_write, keccak_final, keccak_shake_read, + keccak_extract, _gcry_shake128_hash_buffers, sizeof (KECCAK_CONTEXT), run_selftests @@ -1639,8 +1690,9 @@ const gcry_md_spec_t _gcry_digest_spec_shake128 = const gcry_md_spec_t _gcry_digest_spec_shake256 = { GCRY_MD_SHAKE256, {0, 1}, - "SHAKE256", shake256_asn, DIM (shake256_asn), oid_spec_shake256, 0, - shake256_init, keccak_write, keccak_final, NULL, keccak_extract, + "SHAKE256", shake256_asn, DIM (shake256_asn), oid_spec_shake256, 64, + shake256_init, keccak_write, keccak_final, keccak_shake_read, + keccak_extract, _gcry_shake256_hash_buffers, sizeof (KECCAK_CONTEXT), run_selftests diff --git a/cipher/md.c b/cipher/md.c index 40a862f6..a128dd82 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -1125,8 +1125,8 @@ md_extract(gcry_md_hd_t a, int algo, void *out, size_t outlen) { if (r->next) log_debug ("more than one algorithm in md_extract(0)\n"); - r->spec->extract (r->context, out, outlen); - return 0; + + return r->spec->extract (r->context, out, outlen); } } else @@ -1134,8 +1134,7 @@ md_extract(gcry_md_hd_t a, int algo, void *out, size_t outlen) for (r = a->ctx->list; r; r = r->next) if (r->spec->algo == algo && r->spec->extract) { - r->spec->extract (r->context, out, outlen); - return 0; + return r->spec->extract (r->context, out, outlen); } } @@ -1248,6 +1247,7 @@ _gcry_md_hash_buffers_extract (int algo, unsigned int flags, void *digest, int iovcnt) { const gcry_md_spec_t *spec; + int is_xof; int hmac; if (!iov || iovcnt < 0) @@ -1266,11 +1266,13 @@ _gcry_md_hash_buffers_extract (int algo, unsigned int flags, void *digest, return GPG_ERR_DIGEST_ALGO; } - if (spec->mdlen > 0 && digestlen != -1 && digestlen != spec->mdlen) - return GPG_ERR_DIGEST_ALGO; - if (spec->mdlen == 0 && digestlen == -1) + is_xof = spec->extract != NULL; + if (!is_xof && digestlen != -1 && digestlen != spec->mdlen) return GPG_ERR_DIGEST_ALGO; + if (digestlen == -1) + digestlen = spec->mdlen; + if (!hmac && spec->hash_buffers) { if (spec->flags.disabled || (!spec->flags.fips && fips_mode ())) @@ -1304,7 +1306,7 @@ _gcry_md_hash_buffers_extract (int algo, unsigned int flags, void *digest, for (;iovcnt; iov++, iovcnt--) md_write (h, (const char*)iov[0].data + iov[0].off, iov[0].len); md_final (h); - if (spec->mdlen > 0) + if (digestlen == spec->mdlen) memcpy (digest, md_read (h, algo), spec->mdlen); else if (digestlen > 0) md_extract (h, algo, digest, digestlen); diff --git a/src/cipher-proto.h b/src/cipher-proto.h index 3cf6f74c..2d03ed7d 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -216,7 +216,8 @@ typedef void (*gcry_md_final_t) (void *c); typedef unsigned char *(*gcry_md_read_t) (void *c); /* Type for the md_extract function. */ -typedef void (*gcry_md_extract_t) (void *c, void *outbuf, size_t nbytes); +typedef gpg_err_code_t (*gcry_md_extract_t) (void *c, void *outbuf, + size_t nbytes); /* Type for the md_hash_buffers function. */ typedef void (*gcry_md_hash_buffers_t) (void *outbuf, size_t nbytes, diff --git a/tests/basic.c b/tests/basic.c index 5d5ceac9..a405c82c 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -13604,18 +13604,16 @@ check_one_md (int algo, const char *data, int len, const char *expect, int elen, } mdlen = gcry_md_get_algo_dlen (algo); - if (mdlen < 1 || mdlen > 500) + if (elen != 0 && mdlen != elen + && (algo == GCRY_MD_SHAKE128 || algo == GCRY_MD_SHAKE256)) { - if (mdlen == 0 && (algo == GCRY_MD_SHAKE128 || algo == GCRY_MD_SHAKE256)) - { - xof = 1; - } - else - { - gcry_md_close (hd); - fail ("algo %d, gcry_md_get_algo_dlen failed: %d\n", algo, mdlen); - return; - } + xof = 1; + } + else if (mdlen < 1 || mdlen > 500) + { + gcry_md_close (hd); + fail ("algo %d, gcry_md_get_algo_dlen failed: %d\n", algo, mdlen); + return; } if (key && klen) @@ -13942,7 +13940,8 @@ check_one_md (int algo, const char *data, int len, const char *expect, int elen, static void -check_one_md_multi (int algo, const char *data, int len, const char *expect) +check_one_md_multi (int algo, const char *data, int len, const char *expect, + int elen) { gpg_error_t err; gcry_buffer_t iov[3]; @@ -13954,14 +13953,15 @@ check_one_md_multi (int algo, const char *data, int len, const char *expect) mdlen = gcry_md_get_algo_dlen (algo); if (mdlen < 1 || mdlen > 64) { - if (mdlen == 0 && (algo == GCRY_MD_SHAKE128 || algo == GCRY_MD_SHAKE256)) - return; - fail ("check_one_md_multi: algo %d, gcry_md_get_algo_dlen failed: %d\n", algo, mdlen); return; } + if (elen != 0 && elen != mdlen + && (algo == GCRY_MD_SHAKE128 || algo == GCRY_MD_SHAKE256)) + return; + if (*data == '!' && !data[1]) return; /* We can't do that here. */ if (*data == '?' && !data[1]) @@ -14716,6 +14716,11 @@ check_digests (void) "\x43\xE4\x1B\x45\xA6\x53\xF2\xA5\xC4\x49\x2C\x1A\xDD\x54\x45\x12" "\xDD\xA2\x52\x98\x33\x46\x2B\x71\xA4\x1A\x45\xBE\x97\x29\x0B\x6F", 0, 512, }, + { GCRY_MD_SHAKE128, + "", + "\x7F\x9C\x2B\xA4\xE8\x8F\x82\x7D\x61\x60\x45\x50\x76\x05\x85\x3E" + "\xD7\x3B\x80\x93\xF6\xEF\xBC\x88\xEB\x1A\x6E\xAC\xFA\x66\xEF\x26", + 0, 0, /* test md_read interface */ }, { GCRY_MD_SHAKE128, "\x5A\xAB\x62\x75\x6D\x30\x7A\x66\x9D\x14\x6A\xBA\x98\x8D\x90\x74" "\xC5\xA1\x59\xB3\xDE\x85\x15\x1A\x81\x9B\x11\x7C\xA1\xFF\x65\x97" @@ -14834,6 +14839,13 @@ check_digests (void) "\xAB\x0B\xAE\x31\x63\x39\x89\x43\x04\xE3\x58\x77\xB0\xC2\x8A\x9B" "\x1F\xD1\x66\xC7\x96\xB9\xCC\x25\x8A\x06\x4A\x8F\x57\xE2\x7F\x2A", 0, 512, }, + { GCRY_MD_SHAKE256, + "", + "\x46\xB9\xDD\x2B\x0B\xA8\x8D\x13\x23\x3B\x3F\xEB\x74\x3E\xEB\x24" + "\x3F\xCD\x52\xEA\x62\xB8\x1B\x82\xB5\x0C\x27\x64\x6E\xD5\x76\x2F" + "\xD7\x5D\xC4\xDD\xD8\xC0\xF2\x00\xCB\x05\x01\x9D\x67\xB5\x92\xF6" + "\xFC\x82\x1C\x49\x47\x9A\xB4\x86\x40\x29\x2E\xAC\xB3\xB7\xC4\xBE", + 0, 0, /* test md_read interface */ }, { GCRY_MD_SHAKE256, "\xB3\x2D\x95\xB0\xB9\xAA\xD2\xA8\x81\x6D\xE6\xD0\x6D\x1F\x86\x00" "\x85\x05\xBD\x8C\x14\x12\x4F\x6E\x9A\x16\x3B\x5A\x2A\xDE\x55\xF8" @@ -15416,7 +15428,7 @@ check_digests (void) check_one_md_multi (algos[i].md, algos[i].data, algos[i].datalen > 0 ? algos[i].datalen : strlen (algos[i].data), - algos[i].expect); + algos[i].expect, algos[i].expectlen); } /* Check the Whirlpool bug emulation. */ -- 2.39.2 From gniibe at fsij.org Mon Jun 26 08:43:21 2023 From: gniibe at fsij.org (NIIBE Yutaka) Date: Mon, 26 Jun 2023 15:43:21 +0900 Subject: [PATCH] keccak: add md_read support for SHAKE algorithms In-Reply-To: <20230625184623.2235050-1-jussi.kivilinna@iki.fi> References: <20230625184623.2235050-1-jussi.kivilinna@iki.fi> Message-ID: <87r0pywwom.fsf@akagi.fsij.org> Hello, Jussi Kivilinna wrote: > GnuPG-bug-id: 6539 > Signed-off-by: Jussi Kivilinna Thank you for your work. It works well for me. Please go ahead. --