summaryrefslogtreecommitdiff
path: root/sha256/gcrypt.h
AgeCommit message (Collapse)AuthorFilesLines
2026-07-02hash: add platform-specific discard functionsJeff King1-0/+6
Our git_hash_discard() is a bit hacky: it just calls git_hash_final() into a dummy result buffer, using the side effect that each implementation's Final() function will also free any resources. This is probably not too terrible, since generating the final hash is not that expensive and we'd mostly call discard on unusual or error code paths. But we can do better by widening the platform API a bit to add an explicit discard function. This requires an annoying amount of boilerplate: - Each algorithm needs a git_$ALGO_discard() wrapper that dereferences the union'd git_hash_ctx into the type-safe field. So sha1 + sha256 + sha1-unsafe, plus a BUG() for the unknown algo. And then these all need to be referenced in the git_hash_algo structs. - Platforms which don't do anything special to discard now need a fallback function which does nothing. And we need this for each algo (sha1, sha256, and sha1-unsafe). - Platforms which do need to discard must define their discard functions. This includes sha1/openssl, sha256/openssl, and sha256/gcrypt (no sha1-unsafe here as it sits atop the sha1/openssl functions). - Algo selection needs to point platform_*_Discard to the appropriate underlying macro, or indicate that the fallback should be used. We have a similar situation for the Clone function (where a straight memcpy() of the context struct is not enough for some platforms). I've tied Discard to the same flag used by Clone here, since they are basically the same problem: is the hash context a sequence of bytes, or does it need smart copying/discarding? It's easy to miss a case here since we don't even compile the implementations we aren't using. I've tested with each of: - no flags, which uses our internal sha1/sha256 implementations, both of which exercise the noop fallback function - OPENSSL_SHA1_UNSAFE=1, which checks that our unsafe macro redirections work - OPENSSL_SHA1=1, though you should not do that in real life! - OPENSSL_SHA256=1, passes tests with GIT_TEST_DEFAULT_HASH=sha256 - GCRYPT_SHA256=1, which likewise passes The other implementations do not set the CLONE_HELPER flag, so they treat the context as bytes and should be fine with the fallback. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-02hash: fix memory leak copying sha256 gcrypt handlesJeff King1-0/+1
Our abstracted hash-algorithm API allows for cloning a hash context. By default this just memcpy()s the bytes, but specific implementations can provide a custom clone function. Our API is based around the way that OpenSSL works, which is that you first initialize the destination context, then copy into it. In our code that is this: algo->init_fn(&dst); git_hash_clone(&dst, src); and that translates into OpenSSL calls like: /* init_fn */ dst->ectx = EVP_MD_CTX_new(); EVP_DigestInit_ex(dst->ectx, EVP_sha256()); /* clone */ EVP_MD_CTX_copy_ex(dst->ectx, src->ectx); So the allocation happens in the first step, and then the clone is just copying values (the DigestInit is initializing values that just get overwritten, but that's not wrong, just a little inefficient). But libgcrypt doesn't work like that! Its copy function initializes dst from scratch. So when using the sha256 gcrypt backend, that becomes: /* init_fn; this allocates */ gcry_md_open(&dst, GCRY_MD_SHA256); /* clone; this also allocates, leaking the previous value! */ gcry_md_copy(&dst, src); You can see the leaks in the test suite by running: make \ SANITIZE=leak \ GCRYPT_SHA256=1 \ GIT_TEST_DEFAULT_SHA=256 \ test which has many failures, as opposed to building with OPENSSL_SHA256, which is leak-free. The easy fix here is for the clone function to close the open context we're about to overwrite. It's a little inefficient (we did a pointless open in the init function), but probably not a big deal in practice. If our API went the other way, assuming that we're always cloning into garbage bytes, then we could be more efficient. We'd teach OpenSSL's clone function to do its own new(), skip the DigestInit, and then copy into it. And gcrypt could stick with just the copy() call. But look again at the asymmetry in the very first code example. We call the init function straight from the git_hash_algo struct, and then subsequent calls are dispatched through our git_hash_* wrappers. If you wanted to clone into an uninitialized destination, you'd do something like: algo->clone_fn(&dst, src); instead. That would require changing all of the callers. There's not that many of them, but I don't know that it's worth changing our calling conventions to try to reclaim this tiny bit of efficiency. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-07-31sha256/gcrypt: die on gcry_md_open failuresEric Wong1-1/+3
`gcry_md_open' allocates memory and must (like all allocation functions) be checked for failure. Signed-off-by: Eric Wong <e@80x24.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-07-31sha256/gcrypt: fix memory leak with SHA-256 reposEric Wong1-0/+1
`gcry_md_open' needs to be paired with `gcry_md_close' to ensure resources are released. Since our internal APIs don't have separate close/release callbacks, sticking it into the finalization callback seems appropriate. Building with SANITIZE=leak and running `git fsck' on a SHA-256 repository no longer reports leaks. Signed-off-by: Eric Wong <e@80x24.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-07-31sha256/gcrypt: fix build with SANITIZE=leakEric Wong1-4/+4
Non-static functions cause `undefined reference' errors when building with `SANITIZE=leak' due to the lack of prototypes. Mark all these functions as `static inline' as we do in sha256/nettle.h to avoid the need to maintain prototypes. Signed-off-by: Eric Wong <e@80x24.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-24hash: implement and use a context cloning functionbrian m. carlson1-0/+6
For all of our SHA-1 implementations and most of our SHA-256 implementations, the hash context we use is a real struct. For these implementations, it's possible to copy a hash context by making a copy of the struct. However, for our libgcrypt implementation, our hash context is a pointer. Consequently, copying it does not lead to an independent hash context like we intended. Fortunately, however, libgcrypt provides us with a handy function to copy hash contexts. Let's add a cloning function to the hash algorithm API, and use it in the one place we need to make a hash context copy. With this change, our libgcrypt SHA-256 implementation is fully functional with all of our other hash implementations. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-14sha256: add an SHA-256 implementation using libgcryptbrian m. carlson1-0/+30
Generally, one gets better performance out of cryptographic routines written in assembly than C, and this is also true for SHA-256. In addition, most Linux distributions cannot distribute Git linked against OpenSSL for licensing reasons. Most systems with GnuPG will also have libgcrypt, since it is a dependency of GnuPG. libgcrypt is also faster than the SHA1DC implementation for messages of a few KiB and larger. For comparison, on a Core i7-6600U, this implementation processes 16 KiB chunks at 355 MiB/s while SHA1DC processes equivalent chunks at 337 MiB/s. In addition, libgcrypt is licensed under the LGPL 2.1, which is compatible with the GPL. Add an implementation of SHA-256 that uses libgcrypt. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>