* cipher/ecc-eddsa.c (_gcry_ecc_eddsa_compute_h_d, _gcry_ecc_eddsa_sign)
(_gcry_ecc_eddsa_verify): Use same _gcry_md_hash_buffers_extract code path for SHA512 and SHAKE256. * cipher/md.c (_gcry_md_hash_buffers): Rename to ... (_gcry_md_hash_buffers_extract): ... this; Add digestlen and handling for XOF algorithms (SHAKE128, SHAKE256). (_gcry_md_hash_buffers): New. * src/gcrypt-int.h (_gcry_md_hash_buffers_extract): New. -- Signed-off-by: Jussi Kivilinna <[hidden email]> --- cipher/ecc-eddsa.c | 440 +++++++++++++++++---------------------------- cipher/md.c | 51 ++++-- src/gcrypt-int.h | 4 + 3 files changed, 212 insertions(+), 283 deletions(-) diff --git a/cipher/ecc-eddsa.c b/cipher/ecc-eddsa.c index 2a1a8907..baea1bf5 100644 --- a/cipher/ecc-eddsa.c +++ b/cipher/ecc-eddsa.c @@ -500,7 +500,8 @@ _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, mpi_ec_t ec) unsigned char *rawmpi = NULL; unsigned int rawmpilen; unsigned char *digest; - int hashalgo, b; + int hashalgo, b, digestlen; + gcry_buffer_t hvec[2]; *r_digest = NULL; @@ -511,11 +512,15 @@ _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, mpi_ec_t ec) * For now, it's determine by the bit size of the field. */ if (ec->nbits == 255) - hashalgo = GCRY_MD_SHA512; + { + hashalgo = GCRY_MD_SHA512; + digestlen = 64; + } else if (ec->nbits == 448) { b++; hashalgo = GCRY_MD_SHAKE256; + digestlen = 2 * b; } else return GPG_ERR_NOT_IMPLEMENTED; @@ -533,35 +538,14 @@ _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, mpi_ec_t ec) return gpg_err_code_from_syserror (); } - if (hashalgo == GCRY_MD_SHAKE256) - { - gcry_error_t err; - gcry_md_hd_t hd; + memset (hvec, 0, sizeof hvec); - err = _gcry_md_open (&hd, hashalgo, 0); - if (err) - rc = gcry_err_code (err); - else - { - _gcry_md_write (hd, rawmpi, rawmpilen); - _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); - _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); - _gcry_md_close (hd); - rc = 0; - } - } - else - { - gcry_buffer_t hvec[2]; - - memset (hvec, 0, sizeof hvec); - - hvec[0].data = digest; - hvec[0].len = b > rawmpilen? b - rawmpilen : 0; - hvec[1].data = rawmpi; - hvec[1].len = rawmpilen; - rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); - } + hvec[0].data = digest; + hvec[0].len = (hashalgo == GCRY_MD_SHA512 && b > rawmpilen) + ? b - rawmpilen : 0; + hvec[1].data = rawmpi; + hvec[1].len = rawmpilen; + rc = _gcry_md_hash_buffers_extract (hashalgo, 0, digest, digestlen, hvec, 2); xfree (rawmpi); if (rc) @@ -702,16 +686,29 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec, unsigned int encpklen; mpi_point_struct I; /* Intermediate value. */ gcry_mpi_t a, x, y, r; - int b; + const char *dom; + int domlen, digestlen; + int b, i; unsigned char x_olen[2]; unsigned char prehashed_msg[64]; + gcry_buffer_t hvec[6]; + gcry_buffer_t hvec2[1]; b = (ec->nbits+7)/8; if (ec->nbits == 255) - ; + { + dom = DOM25519; + domlen = DOM25519_LEN; + digestlen = 64; + } else if (ec->nbits == 448) - b++; + { + b++; + dom = DOM448; + domlen = DOM448_LEN; + digestlen = 2 * b; + } else return GPG_ERR_NOT_IMPLEMENTED; @@ -751,98 +748,58 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec, if (DBG_CIPHER) log_printhex (" m", mbuf, mlen); - if (ctx->hash_algo == GCRY_MD_SHAKE256) + memset (hvec, 0, sizeof hvec); + i = 0; + + if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448) { - gcry_error_t err; - gcry_md_hd_t hd; + hvec[i].data = (void *)dom; + hvec[i].len = domlen; + i++; + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + hvec[i].data = x_olen; + hvec[i].len = 2; + i++; + if (ctx->labellen) + { + hvec[i].data = ctx->label; + hvec[i].len = ctx->labellen; + i++; + } + } - err = _gcry_md_open (&hd, ctx->hash_algo, 0); - if (err) - rc = gcry_err_code (err); - else - { - _gcry_md_write (hd, DOM448, DOM448_LEN); - x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); - x_olen[1] = ctx->labellen; - _gcry_md_write (hd, x_olen, 2); - if (ctx->labellen) - _gcry_md_write (hd, ctx->label, ctx->labellen); - _gcry_md_write (hd, digest+b, b); - if ((ctx->flags & PUBKEY_FLAG_PREHASH)) - { - gcry_md_hd_t hd2; + hvec[i].data = digest; + hvec[i].off = b; + hvec[i].len = b; + i++; + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + { + memset (hvec2, 0, sizeof hvec2); - err = _gcry_md_open (&hd2, ctx->hash_algo, 0); - if (err) - { - rc = gcry_err_code (err); - _gcry_md_close (hd); - goto leave; - } - _gcry_md_write (hd2, mbuf, mlen); - _gcry_md_ctl (hd2, GCRYCTL_FINALIZE, NULL, 0); - _gcry_md_extract (hd2, GCRY_MD_SHAKE256, prehashed_msg, 64); - _gcry_md_close (hd2); - _gcry_md_write (hd, prehashed_msg, 64); - } - else - _gcry_md_write (hd, mbuf, mlen); - _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); - _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); - _gcry_md_close (hd); - rc = 0; - } + hvec2[0].data = (char*)mbuf; + hvec2[0].len = mlen; + + _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, prehashed_msg, 64, + hvec2, 1); + hvec[i].data = (char*)prehashed_msg; + hvec[i].len = 64; } else { - gcry_buffer_t hvec[6]; - int i = 0; - - memset (hvec, 0, sizeof hvec); - - if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen) - { - hvec[i].data = (void *)DOM25519; - hvec[i].len = DOM25519_LEN; - i++; - x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); - x_olen[1] = ctx->labellen; - hvec[i].data = x_olen; - hvec[i].len = 2; - i++; - if (ctx->labellen) - { - hvec[i].data = ctx->label; - hvec[i].len = ctx->labellen; - i++; - } - } - - hvec[i].data = digest; - hvec[i].off = b; - hvec[i].len = b; - i++; - if ((ctx->flags & PUBKEY_FLAG_PREHASH)) - { - _gcry_md_hash_buffer (ctx->hash_algo, prehashed_msg, mbuf, mlen); - hvec[i].data = (char*)prehashed_msg; - hvec[i].len = 64; - } - else - { - hvec[i].data = (char*)mbuf; - hvec[i].len = mlen; - } - i++; - rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i); + hvec[i].data = (char*)mbuf; + hvec[i].len = mlen; } + i++; + rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen, + hvec, i); if (rc) goto leave; - reverse_buffer (digest, 2*b); + reverse_buffer (digest, digestlen); if (DBG_CIPHER) - log_printhex (" r", digest, 2*b); - _gcry_mpi_set_buffer (r, digest, 2*b, 0); + log_printhex (" r", digest, digestlen); + _gcry_mpi_set_buffer (r, digest, digestlen, 0); mpi_mod (r, r, ec->n); _gcry_mpi_ec_mul_point (&I, r, ec->G, ec); if (DBG_CIPHER) @@ -855,80 +812,48 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec, if (DBG_CIPHER) log_printhex (" e_r", rawmpi, rawmpilen); - if (ctx->hash_algo == GCRY_MD_SHAKE256) + memset (hvec, 0, sizeof hvec); + i = 0; + + if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448) { - gcry_error_t err; - gcry_md_hd_t hd; + hvec[i].data = (void *)dom; + hvec[i].len = domlen; + i++; + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + hvec[i].data = x_olen; + hvec[i].len = 2; + i++; + if (ctx->labellen) + { + hvec[i].data = ctx->label; + hvec[i].len = ctx->labellen; + i++; + } + } - err = _gcry_md_open (&hd, ctx->hash_algo, 0); - if (err) - rc = gcry_err_code (err); - else - { - _gcry_md_write (hd, DOM448, DOM448_LEN); - x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); - x_olen[1] = ctx->labellen; - _gcry_md_write (hd, x_olen, 2); - if (ctx->labellen) - _gcry_md_write (hd, ctx->label, ctx->labellen); - _gcry_md_write (hd, rawmpi, rawmpilen); - _gcry_md_write (hd, encpk, encpklen); - if ((ctx->flags & PUBKEY_FLAG_PREHASH)) - _gcry_md_write (hd, prehashed_msg, 64); - else - _gcry_md_write (hd, mbuf, mlen); - _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); - _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); - _gcry_md_close (hd); - rc = 0; - } + /* S = r + a * H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) mod n */ + hvec[i].data = rawmpi; /* (this is R) */ + hvec[i].len = rawmpilen; + i++; + hvec[i].data = encpk; + hvec[i].len = encpklen; + i++; + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + { + hvec[i].data = (char*)prehashed_msg; + hvec[i].len = 64; } else { - gcry_buffer_t hvec[6]; - int i = 0; - - memset (hvec, 0, sizeof hvec); - - if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen) - { - hvec[i].data = (void *)DOM25519; - hvec[i].len = DOM25519_LEN; - i++; - x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); - x_olen[1] = ctx->labellen; - hvec[i].data = x_olen; - hvec[i].len = 2; - i++; - if (ctx->labellen) - { - hvec[i].data = ctx->label; - hvec[i].len = ctx->labellen; - i++; - } - } - - /* S = r + a * H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) mod n */ - hvec[i].data = rawmpi; /* (this is R) */ - hvec[i].len = rawmpilen; - i++; - hvec[i].data = encpk; - hvec[i].len = encpklen; - i++; - if ((ctx->flags & PUBKEY_FLAG_PREHASH)) - { - hvec[i].data = (char*)prehashed_msg; - hvec[i].len = 64; - } - else - { - hvec[i].data = (char*)mbuf; - hvec[i].len = mlen; - } - i++; - rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i); + hvec[i].data = (char*)mbuf; + hvec[i].len = mlen; } + i++; + rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen, + hvec, i); if (rc) goto leave; @@ -936,10 +861,10 @@ _gcry_ecc_eddsa_sign (gcry_mpi_t input, mpi_ec_t ec, mpi_set_opaque (r_r, rawmpi, rawmpilen*8); rawmpi = NULL; - reverse_buffer (digest, 2*b); + reverse_buffer (digest, digestlen); if (DBG_CIPHER) - log_printhex (" H(R+)", digest, 2*b); - _gcry_mpi_set_buffer (s, digest, 2*b, 0); + log_printhex (" H(R+)", digest, digestlen); + _gcry_mpi_set_buffer (s, digest, digestlen, 0); mpi_mulm (s, s, a, ec->n); mpi_addm (s, s, r, ec->n); rc = eddsa_encodempi (s, ec->nbits, &rawmpi, &rawmpilen); @@ -985,8 +910,13 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, mpi_ec_t ec, unsigned char digest[114]; gcry_mpi_t h, s; mpi_point_struct Ia, Ib; + const char *dom; + int domlen, digestlen; + int i; unsigned char x_olen[2]; unsigned char prehashed_msg[64]; + gcry_buffer_t hvec[6]; + gcry_buffer_t hvec2[1]; if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in)) return GPG_ERR_INV_DATA; @@ -999,9 +929,18 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, mpi_ec_t ec, b = (ec->nbits+7)/8; if (ec->nbits == 255) - ; + { + dom = DOM25519; + domlen = DOM25519_LEN; + digestlen = 64; + } else if (ec->nbits == 448) - b++; + { + b++; + dom = DOM448; + domlen = DOM448_LEN; + digestlen = 2 * b; + } else return GPG_ERR_NOT_IMPLEMENTED; @@ -1038,102 +977,61 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, mpi_ec_t ec, goto leave; } - if (ctx->hash_algo == GCRY_MD_SHAKE256) + memset (hvec, 0, sizeof hvec); + i = 0; + + /* h = H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) */ + if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen || ec->nbits == 448) { - gcry_error_t err; - gcry_md_hd_t hd; + hvec[i].data = (void *)dom; + hvec[i].len = domlen; + i++; + x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); + x_olen[1] = ctx->labellen; + hvec[i].data = x_olen; + hvec[i].len = 2; + i++; + if (ctx->labellen) + { + hvec[i].data = ctx->label; + hvec[i].len = ctx->labellen; + i++; + } + } - err = _gcry_md_open (&hd, ctx->hash_algo, 0); - if (err) - rc = gcry_err_code (err); - else - { - _gcry_md_write (hd, DOM448, DOM448_LEN); - x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); - x_olen[1] = ctx->labellen; - _gcry_md_write (hd, x_olen, 2); - if (ctx->labellen) - _gcry_md_write (hd, ctx->label, ctx->labellen); - _gcry_md_write (hd, rbuf, rlen); - _gcry_md_write (hd, encpk, encpklen); - if ((ctx->flags & PUBKEY_FLAG_PREHASH)) - { - gcry_md_hd_t hd2; + hvec[i].data = (char*)rbuf; + hvec[i].len = rlen; + i++; + hvec[i].data = encpk; + hvec[i].len = encpklen; + i++; + if ((ctx->flags & PUBKEY_FLAG_PREHASH)) + { + memset (hvec2, 0, sizeof hvec2); - err = _gcry_md_open (&hd2, ctx->hash_algo, 0); - if (err) - { - rc = gcry_err_code (err); - _gcry_md_close (hd); - goto leave; - } - _gcry_md_write (hd2, mbuf, mlen); - _gcry_md_ctl (hd2, GCRYCTL_FINALIZE, NULL, 0); - _gcry_md_extract (hd2, GCRY_MD_SHAKE256, prehashed_msg, 64); - _gcry_md_close (hd2); - _gcry_md_write (hd, prehashed_msg, 64); - } - else - _gcry_md_write (hd, mbuf, mlen); - _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); - _gcry_md_extract (hd, GCRY_MD_SHAKE256, digest, 2*b); - _gcry_md_close (hd); - rc = 0; - } + hvec2[0].data = (char*)mbuf; + hvec2[0].len = mlen; + + _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, prehashed_msg, 64, + hvec2, 1); + hvec[i].data = (char*)prehashed_msg; + hvec[i].len = 64; } else { - gcry_buffer_t hvec[6]; - int i = 0; - - memset (hvec, 0, sizeof hvec); - - /* h = H(dom2(F,C)+encodepoint(R)+encodepoint(pk)+m) */ - if ((ctx->flags & PUBKEY_FLAG_PREHASH) || ctx->labellen) - { - hvec[i].data = (void *)DOM25519; - hvec[i].len = DOM25519_LEN; - i++; - x_olen[0] = !!(ctx->flags & PUBKEY_FLAG_PREHASH); - x_olen[1] = ctx->labellen; - hvec[i].data = x_olen; - hvec[i].len = 2; - i++; - if (ctx->labellen) - { - hvec[i].data = ctx->label; - hvec[i].len = ctx->labellen; - i++; - } - } - - hvec[i].data = (char*)rbuf; - hvec[i].len = rlen; - i++; - hvec[i].data = encpk; - hvec[i].len = encpklen; - i++; - if ((ctx->flags & PUBKEY_FLAG_PREHASH)) - { - _gcry_md_hash_buffer (ctx->hash_algo, prehashed_msg, mbuf, mlen); - hvec[i].data = (char*)prehashed_msg; - hvec[i].len = 64; - } - else - { - hvec[i].data = (char*)mbuf; - hvec[i].len = mlen; - } - i++; - rc = _gcry_md_hash_buffers (ctx->hash_algo, 0, digest, hvec, i); + hvec[i].data = (char*)mbuf; + hvec[i].len = mlen; } + i++; + rc = _gcry_md_hash_buffers_extract (ctx->hash_algo, 0, digest, digestlen, + hvec, i); if (rc) goto leave; - reverse_buffer (digest, 2*b); + reverse_buffer (digest, digestlen); if (DBG_CIPHER) - log_printhex (" H(R+)", digest, 2*b); - _gcry_mpi_set_buffer (h, digest, 2*b, 0); + log_printhex (" H(R+)", digest, digestlen); + _gcry_mpi_set_buffer (h, digest, digestlen, 0); /* According to the paper the best way for verification is: encodepoint(sG - h·Q) = encodepoint(r) diff --git a/cipher/md.c b/cipher/md.c index efb7376a..87979059 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -1251,11 +1251,15 @@ _gcry_md_hash_buffer (int algo, void *digest, used as the key. On success 0 is returned and resulting hash or HMAC is stored at - DIGEST which must have been provided by the caller with an - appropriate length. */ + DIGEST. DIGESTLEN may be given as -1, in which case DIGEST must + have been provided by the caller with an appropriate length. + DIGESTLEN may also be the appropriate length or, in case of XOF + algorithms, DIGESTLEN indicates number bytes to extract from XOF + to DIGEST. */ gpg_err_code_t -_gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, - const gcry_buffer_t *iov, int iovcnt) +_gcry_md_hash_buffers_extract (int algo, unsigned int flags, void *digest, + int digestlen, const gcry_buffer_t *iov, + int iovcnt) { gcry_md_spec_t *spec; int hmac; @@ -1287,6 +1291,11 @@ _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, } } + if (spec->mdlen > 0 && digestlen != -1 && digestlen != spec->mdlen) + return GPG_ERR_DIGEST_ALGO; + if (spec->mdlen == 0 && digestlen == -1) + return GPG_ERR_DIGEST_ALGO; + if (!hmac && spec->hash_buffers) { spec->hash_buffers (digest, iov, iovcnt); @@ -1297,13 +1306,6 @@ _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, normal functions. */ gcry_md_hd_t h; gpg_err_code_t rc; - int dlen; - - /* Detect SHAKE128 like algorithms which we can't use because - * our API does not allow for a variable length digest. */ - dlen = md_digest_length (algo); - if (!dlen) - return GPG_ERR_DIGEST_ALGO; rc = md_open (&h, algo, (hmac? GCRY_MD_FLAG_HMAC:0)); if (rc) @@ -1324,7 +1326,10 @@ _gcry_md_hash_buffers (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); - memcpy (digest, md_read (h, algo), dlen); + if (spec->mdlen > 0) + memcpy (digest, md_read (h, algo), spec->mdlen); + else if (digestlen > 0) + md_extract (h, algo, digest, digestlen); md_close (h); } @@ -1332,6 +1337,28 @@ _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, } +/* Shortcut function to hash multiple buffers with a given algo. In + contrast to gcry_md_hash_buffer, this function returns an error on + invalid arguments or on other problems; disabled algorithms are + _not_ ignored but flagged as an error. + + The data to sign is taken from the array IOV which has IOVCNT items. + + The only supported flag in FLAGS is GCRY_MD_FLAG_HMAC which turns + this function into a HMAC function; the first item in IOV is then + used as the key. + + On success 0 is returned and resulting hash or HMAC is stored at + DIGEST which must have been provided by the caller with an + appropriate length. */ +gpg_err_code_t +_gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, + const gcry_buffer_t *iov, int iovcnt) +{ + return _gcry_md_hash_buffers_extract(algo, flags, digest, -1, iov, iovcnt); +} + + static int md_get_algo (gcry_md_hd_t a) { diff --git a/src/gcrypt-int.h b/src/gcrypt-int.h index 086953d7..d8b6d407 100644 --- a/src/gcrypt-int.h +++ b/src/gcrypt-int.h @@ -128,6 +128,10 @@ gpg_err_code_t _gcry_md_extract (gcry_md_hd_t hd, int algo, void *buffer, size_t length); void _gcry_md_hash_buffer (int algo, void *digest, const void *buffer, size_t length); +gpg_err_code_t _gcry_md_hash_buffers_extract (int algo, unsigned int flags, + void *digest, int digestlen, + const gcry_buffer_t *iov, + int iovcnt); gpg_err_code_t _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, const gcry_buffer_t *iov, int iovcnt); -- 2.27.0 _______________________________________________ Gcrypt-devel mailing list [hidden email] http://lists.gnupg.org/mailman/listinfo/gcrypt-devel |
Free forum by Nabble | Edit this page |