git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/6] Additional SHA implementations
@ 2019-12-22  6:48 Michael Clark
  2019-12-22  6:48 ` [PATCH 1/6] Move all SHA algorithm variants into sha/ directory Michael Clark
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Michael Clark @ 2019-12-22  6:48 UTC (permalink / raw)
  To: git; +Cc: Michael Clark

Hi Folks,

I have been investigating performance and security of alternative hash
algorithms in git, and while doing so, have added algorithm alternatives
to git to allow testing them out to see how they affect performance.

I have been thinking that it might not be ideal to add lots of algorithm
variants to git so as to reduce potential future incompatibility,
however, that is another discussion. The algorithms need to be added
to test out performance, and this patch series is for anyone interested
in testing out alternative algorithms. While it is necessary to have
mandatory hashes for compatibility, there are potential use-cases where
alternative hashes might be beneficial. There is also the possibility
of N-hash support when implementing compatObjectFormat as outlined in
Git hash function transition [1].

This patch series adds to the generic hash algorithm interface in git
with two new hash algorithms: SHA512 (including SHA512/224, SHA512/256)
and SHA3. The patch also adds SHA224 (truncated SHA256) and add internal
implementations for the two new hashes as well as library wrappers.
THe SHA512 block digest function is derived from the existing SHA256
implementation, modified for 64-bit, as well as the truncated forms.

- moves existing SHA code into sha/ directory
- adds new SHA512 implementation (based on existing SHA256 impl)
- adds new SHA3 implementation (based on NIST submission)
- adds gcrypt library interfaces (`make GCRYPT_SHA512=1 GCRYPT_SHA3=1`)
- adds OpenSSL EVP interfaces (`make OPENSSL_EVP=1`)
- adds test cipher commands to test-tool
- adds test vectors to t/t0015-hash.sh
- adds empty tree and blob hashes using pre-existing scheme

It seems that muliple hash function support would have more utility if
the additional computed hashes were the pure hash of the unpacked
object, instead of compressed and prefixed object data. In any case,
I can see several potential uses for the alternative hash algorithms.

Noticed that the current empty tree and empty blob have the length
prefixes ("blob 0\0" and "tree 0\0") which may or may not be required
with new hashes given that they have length extension resistance?

This series adds almost all known SHA variants so that folk who are
working on abstracting away support for new algos can easily try
alternatives. The algos added by this patch series are not exposed
to the user in any way, and require changes to .hash_algo in cache.h
to enable them, so they should not cause any compatibility issues,
rather just extend the in-tree API.

We could perhaps add options so they are not compiled by default.

This table shows the algorithm type codes after the series is applied:

| algorithm      | type-code | integer-code |
| -------------- | --------- | ------------ |
| "sha1"         | "sha1"    | 0x73686131   |
| "sha224"       | "s224"    | 0x73323234   |
| "sha256"       | "s256"    | 0x73323536   |
| "sha512"       | "s512"    | 0x73353132   |
| "sha512/224"   | "s226"    | 0x73323236   |
| "sha512/256"   | "s228"    | 0x73323238   |
| "sha3-224"     | "s388"    | 0x73323234   |
| "sha3-256"     | "s398"    | 0x73323536   |
| "sha3-384"     | "s3a8"    | 0x73336834   |
| "sha3-512"     | "s3b8"    | 0x73356132   |

I hope you find these patches useful.

Regards,

Michael

[1] https://github.com/git/git/blob/master/Documentation/technical/hash-function-transition.txt

Michael Clark (6):
  Move all SHA algorithm variants into sha/ directory
  Add an implementation of the SHA-512 hash algorithm
  Add an implementation of the SHA-3 hash algorithm
  Add an implementation of the SHA224 truncated hash algorithm
  Add OpenSSL EVP interface for SHA-3 and SHA-512 algorithms
  Add sha/README.md with table of SHA algorithm details

 Makefile                              |  46 +++-
 hash.h                                | 125 ++++++++++-
 sha/README.md                         |  23 ++
 {block-sha1 => sha/sha1}/sha1.c       |   2 +-
 {block-sha1 => sha/sha1}/sha1.h       |   0
 {sha1dc => sha/sha1dc}/.gitattributes |   0
 {sha1dc => sha/sha1dc}/LICENSE.txt    |   0
 {sha1dc => sha/sha1dc}/sha1.c         |   0
 {sha1dc => sha/sha1dc}/sha1.h         |   0
 {sha1dc => sha/sha1dc}/ubc_check.c    |   0
 {sha1dc => sha/sha1dc}/ubc_check.h    |   0
 sha1dc_git.c => sha/sha1dc_git.c      |   0
 sha1dc_git.h => sha/sha1dc_git.h      |   2 +-
 {ppc => sha/sha1ppc}/sha1.c           |   0
 {ppc => sha/sha1ppc}/sha1.h           |   0
 {ppc => sha/sha1ppc}/sha1ppc.S        |   0
 {sha256 => sha/sha256}/gcrypt.h       |  15 +-
 {sha256/block => sha/sha256}/sha256.c |  18 +-
 {sha256/block => sha/sha256}/sha256.h |   9 +
 sha/sha3/gcrypt.h                     |  53 +++++
 sha/sha3/sha3.c                       | 271 ++++++++++++++++++++++
 sha/sha3/sha3.h                       |  34 +++
 sha/sha512/gcrypt.h                   |  43 ++++
 sha/sha512/sha512.c                   | 206 +++++++++++++++++
 sha/sha512/sha512.h                   |  31 +++
 sha/sha_evp/sha_evp.c                 |  99 +++++++++
 sha/sha_evp/sha_evp.h                 |  51 +++++
 sha1-file.c                           | 309 ++++++++++++++++++++++++++
 t/helper/test-sha256.c                |   5 +
 t/helper/test-sha3.c                  |  22 ++
 t/helper/test-sha512.c                |  17 ++
 t/helper/test-tool.c                  |   8 +
 t/helper/test-tool.h                  |   8 +
 t/t0015-hash.sh                       | 214 ++++++++++++++++++
 34 files changed, 1592 insertions(+), 19 deletions(-)
 create mode 100644 sha/README.md
 rename {block-sha1 => sha/sha1}/sha1.c (99%)
 rename {block-sha1 => sha/sha1}/sha1.h (100%)
 rename {sha1dc => sha/sha1dc}/.gitattributes (100%)
 rename {sha1dc => sha/sha1dc}/LICENSE.txt (100%)
 rename {sha1dc => sha/sha1dc}/sha1.c (100%)
 rename {sha1dc => sha/sha1dc}/sha1.h (100%)
 rename {sha1dc => sha/sha1dc}/ubc_check.c (100%)
 rename {sha1dc => sha/sha1dc}/ubc_check.h (100%)
 rename sha1dc_git.c => sha/sha1dc_git.c (100%)
 rename sha1dc_git.h => sha/sha1dc_git.h (95%)
 rename {ppc => sha/sha1ppc}/sha1.c (100%)
 rename {ppc => sha/sha1ppc}/sha1.h (100%)
 rename {ppc => sha/sha1ppc}/sha1ppc.S (100%)
 rename {sha256 => sha/sha256}/gcrypt.h (58%)
 rename {sha256/block => sha/sha256}/sha256.c (93%)
 rename {sha256/block => sha/sha256}/sha256.h (67%)
 create mode 100644 sha/sha3/gcrypt.h
 create mode 100644 sha/sha3/sha3.c
 create mode 100644 sha/sha3/sha3.h
 create mode 100644 sha/sha512/gcrypt.h
 create mode 100644 sha/sha512/sha512.c
 create mode 100644 sha/sha512/sha512.h
 create mode 100644 sha/sha_evp/sha_evp.c
 create mode 100644 sha/sha_evp/sha_evp.h
 create mode 100644 t/helper/test-sha3.c
 create mode 100644 t/helper/test-sha512.c

-- 
2.20.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/6] Move all SHA algorithm variants into sha/ directory
  2019-12-22  6:48 [PATCH 0/6] Additional SHA implementations Michael Clark
@ 2019-12-22  6:48 ` Michael Clark
  2019-12-22  6:48 ` [PATCH 2/6] Add an implementation of the SHA-512 hash algorithm Michael Clark
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Michael Clark @ 2019-12-22  6:48 UTC (permalink / raw)
  To: git; +Cc: Michael Clark

This is a tidy up before we add additional hash agorithms.
This patch does not change code. It only contains renames.

After this patch, all hash algorithm implementations are in sha/.
---
 Makefile                              | 16 ++++++++--------
 hash.h                                |  6 +++---
 {block-sha1 => sha/sha1}/sha1.c       |  2 +-
 {block-sha1 => sha/sha1}/sha1.h       |  0
 {sha1dc => sha/sha1dc}/.gitattributes |  0
 {sha1dc => sha/sha1dc}/LICENSE.txt    |  0
 {sha1dc => sha/sha1dc}/sha1.c         |  0
 {sha1dc => sha/sha1dc}/sha1.h         |  0
 {sha1dc => sha/sha1dc}/ubc_check.c    |  0
 {sha1dc => sha/sha1dc}/ubc_check.h    |  0
 sha1dc_git.c => sha/sha1dc_git.c      |  0
 sha1dc_git.h => sha/sha1dc_git.h      |  2 +-
 {ppc => sha/sha1ppc}/sha1.c           |  0
 {ppc => sha/sha1ppc}/sha1.h           |  0
 {ppc => sha/sha1ppc}/sha1ppc.S        |  0
 {sha256 => sha/sha256}/gcrypt.h       |  0
 {sha256/block => sha/sha256}/sha256.c |  0
 {sha256/block => sha/sha256}/sha256.h |  0
 18 files changed, 13 insertions(+), 13 deletions(-)
 rename {block-sha1 => sha/sha1}/sha1.c (99%)
 rename {block-sha1 => sha/sha1}/sha1.h (100%)
 rename {sha1dc => sha/sha1dc}/.gitattributes (100%)
 rename {sha1dc => sha/sha1dc}/LICENSE.txt (100%)
 rename {sha1dc => sha/sha1dc}/sha1.c (100%)
 rename {sha1dc => sha/sha1dc}/sha1.h (100%)
 rename {sha1dc => sha/sha1dc}/ubc_check.c (100%)
 rename {sha1dc => sha/sha1dc}/ubc_check.h (100%)
 rename sha1dc_git.c => sha/sha1dc_git.c (100%)
 rename sha1dc_git.h => sha/sha1dc_git.h (95%)
 rename {ppc => sha/sha1ppc}/sha1.c (100%)
 rename {ppc => sha/sha1ppc}/sha1.h (100%)
 rename {ppc => sha/sha1ppc}/sha1ppc.S (100%)
 rename {sha256 => sha/sha256}/gcrypt.h (100%)
 rename {sha256/block => sha/sha256}/sha256.c (100%)
 rename {sha256/block => sha/sha256}/sha256.h (100%)

diff --git a/Makefile b/Makefile
index 42a061d3fb75..bac1b30b2f1f 100644
--- a/Makefile
+++ b/Makefile
@@ -1158,7 +1158,7 @@ THIRD_PARTY_SOURCES += compat/obstack.%
 THIRD_PARTY_SOURCES += compat/poll/%
 THIRD_PARTY_SOURCES += compat/regex/%
 THIRD_PARTY_SOURCES += sha1collisiondetection/%
-THIRD_PARTY_SOURCES += sha1dc/%
+THIRD_PARTY_SOURCES += sha/sha1dc/%
 
 GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB)
 EXTLIBS =
@@ -1657,11 +1657,11 @@ ifdef OPENSSL_SHA1
 	BASIC_CFLAGS += -DSHA1_OPENSSL
 else
 ifdef BLK_SHA1
-	LIB_OBJS += block-sha1/sha1.o
+	LIB_OBJS += sha/sha1/sha1.o
 	BASIC_CFLAGS += -DSHA1_BLK
 else
 ifdef PPC_SHA1
-	LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
+	LIB_OBJS += sha/sha1ppc/sha1.o sha/sha1ppc/sha1ppc.o
 	BASIC_CFLAGS += -DSHA1_PPC
 else
 ifdef APPLE_COMMON_CRYPTO
@@ -1670,7 +1670,7 @@ ifdef APPLE_COMMON_CRYPTO
 else
 	DC_SHA1 := YesPlease
 	BASIC_CFLAGS += -DSHA1_DC
-	LIB_OBJS += sha1dc_git.o
+	LIB_OBJS += sha/sha1dc_git.o
 ifdef DC_SHA1_EXTERNAL
 	ifdef DC_SHA1_SUBMODULE
 		ifneq ($(DC_SHA1_SUBMODULE),auto)
@@ -1685,8 +1685,8 @@ ifdef DC_SHA1_SUBMODULE
 	LIB_OBJS += sha1collisiondetection/lib/ubc_check.o
 	BASIC_CFLAGS += -DDC_SHA1_SUBMODULE
 else
-	LIB_OBJS += sha1dc/sha1.o
-	LIB_OBJS += sha1dc/ubc_check.o
+	LIB_OBJS += sha/sha1dc/sha1.o
+	LIB_OBJS += sha/sha1dc/ubc_check.o
 endif
 	BASIC_CFLAGS += \
 		-DSHA1DC_NO_STANDARD_INCLUDES \
@@ -1707,7 +1707,7 @@ ifdef GCRYPT_SHA256
 	BASIC_CFLAGS += -DSHA256_GCRYPT
 	EXTLIBS += -lgcrypt
 else
-	LIB_OBJS += sha256/block/sha256.o
+	LIB_OBJS += sha/sha256/sha256.o
 	BASIC_CFLAGS += -DSHA256_BLK
 endif
 endif
@@ -2782,7 +2782,7 @@ sparse: $(SP_OBJ)
 GEN_HDRS := command-list.h unicode-width.h
 EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%
 ifndef GCRYPT_SHA256
-	EXCEPT_HDRS += sha256/gcrypt.h
+	EXCEPT_HDRS += sha/sha256/gcrypt.h
 endif
 CHK_HDRS = $(filter-out $(EXCEPT_HDRS),$(LIB_H))
 HCO = $(patsubst %.h,%.hco,$(CHK_HDRS))
diff --git a/hash.h b/hash.h
index 52a4f1a3f430..f1b941218dc8 100644
--- a/hash.h
+++ b/hash.h
@@ -10,9 +10,9 @@
 #elif defined(SHA1_OPENSSL)
 #include <openssl/sha.h>
 #elif defined(SHA1_DC)
-#include "sha1dc_git.h"
+#include "sha/sha1dc_git.h"
 #else /* SHA1_BLK */
-#include "block-sha1/sha1.h"
+#include "sha/sha1/sha1.h"
 #endif
 
 #if defined(SHA256_GCRYPT)
@@ -20,7 +20,7 @@
 #elif defined(SHA256_OPENSSL)
 #include <openssl/sha.h>
 #else
-#include "sha256/block/sha256.h"
+#include "sha/sha256/sha256.h"
 #endif
 
 #ifndef platform_SHA_CTX
diff --git a/block-sha1/sha1.c b/sha/sha1/sha1.c
similarity index 99%
rename from block-sha1/sha1.c
rename to sha/sha1/sha1.c
index 22b125cf8c12..ad9f7e50a395 100644
--- a/block-sha1/sha1.c
+++ b/sha/sha1/sha1.c
@@ -7,7 +7,7 @@
  */
 
 /* this is only to get definitions for memcpy(), ntohl() and htonl() */
-#include "../git-compat-util.h"
+#include "git-compat-util.h"
 
 #include "sha1.h"
 
diff --git a/block-sha1/sha1.h b/sha/sha1/sha1.h
similarity index 100%
rename from block-sha1/sha1.h
rename to sha/sha1/sha1.h
diff --git a/sha1dc/.gitattributes b/sha/sha1dc/.gitattributes
similarity index 100%
rename from sha1dc/.gitattributes
rename to sha/sha1dc/.gitattributes
diff --git a/sha1dc/LICENSE.txt b/sha/sha1dc/LICENSE.txt
similarity index 100%
rename from sha1dc/LICENSE.txt
rename to sha/sha1dc/LICENSE.txt
diff --git a/sha1dc/sha1.c b/sha/sha1dc/sha1.c
similarity index 100%
rename from sha1dc/sha1.c
rename to sha/sha1dc/sha1.c
diff --git a/sha1dc/sha1.h b/sha/sha1dc/sha1.h
similarity index 100%
rename from sha1dc/sha1.h
rename to sha/sha1dc/sha1.h
diff --git a/sha1dc/ubc_check.c b/sha/sha1dc/ubc_check.c
similarity index 100%
rename from sha1dc/ubc_check.c
rename to sha/sha1dc/ubc_check.c
diff --git a/sha1dc/ubc_check.h b/sha/sha1dc/ubc_check.h
similarity index 100%
rename from sha1dc/ubc_check.h
rename to sha/sha1dc/ubc_check.h
diff --git a/sha1dc_git.c b/sha/sha1dc_git.c
similarity index 100%
rename from sha1dc_git.c
rename to sha/sha1dc_git.c
diff --git a/sha1dc_git.h b/sha/sha1dc_git.h
similarity index 95%
rename from sha1dc_git.h
rename to sha/sha1dc_git.h
index 41e1c3fd3f78..100a7cc9d641 100644
--- a/sha1dc_git.h
+++ b/sha/sha1dc_git.h
@@ -5,7 +5,7 @@
 #elif defined(DC_SHA1_SUBMODULE)
 #include "sha1collisiondetection/lib/sha1.h"
 #else
-#include "sha1dc/sha1.h"
+#include "sha/sha1dc/sha1.h"
 #endif
 
 #ifdef DC_SHA1_EXTERNAL
diff --git a/ppc/sha1.c b/sha/sha1ppc/sha1.c
similarity index 100%
rename from ppc/sha1.c
rename to sha/sha1ppc/sha1.c
diff --git a/ppc/sha1.h b/sha/sha1ppc/sha1.h
similarity index 100%
rename from ppc/sha1.h
rename to sha/sha1ppc/sha1.h
diff --git a/ppc/sha1ppc.S b/sha/sha1ppc/sha1ppc.S
similarity index 100%
rename from ppc/sha1ppc.S
rename to sha/sha1ppc/sha1ppc.S
diff --git a/sha256/gcrypt.h b/sha/sha256/gcrypt.h
similarity index 100%
rename from sha256/gcrypt.h
rename to sha/sha256/gcrypt.h
diff --git a/sha256/block/sha256.c b/sha/sha256/sha256.c
similarity index 100%
rename from sha256/block/sha256.c
rename to sha/sha256/sha256.c
diff --git a/sha256/block/sha256.h b/sha/sha256/sha256.h
similarity index 100%
rename from sha256/block/sha256.h
rename to sha/sha256/sha256.h
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/6] Add an implementation of the SHA-512 hash algorithm
  2019-12-22  6:48 [PATCH 0/6] Additional SHA implementations Michael Clark
  2019-12-22  6:48 ` [PATCH 1/6] Move all SHA algorithm variants into sha/ directory Michael Clark
@ 2019-12-22  6:48 ` Michael Clark
  2019-12-22  6:48 ` [PATCH 3/6] Add an implementation of the SHA-3 " Michael Clark
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Michael Clark @ 2019-12-22  6:48 UTC (permalink / raw)
  To: git; +Cc: Michael Clark

- Add SHA-512 hash algorithm implementation derived from the
  SHA-256 implementation translated to 64-bit and 80 rounds.
- Add configuration machinery to select builtin impl or gcrypt.
- Add sha512-224, sha512-256 and sha512 commands to test-tool.
- Add sha512 hash tests to t/t0015-hash.sh
---
 Makefile               |  14 +++
 hash.h                 |  46 ++++++-
 sha/sha512/gcrypt.h    |  43 +++++++
 sha/sha512/sha512.c    | 206 +++++++++++++++++++++++++++++++
 sha/sha512/sha512.h    |  31 +++++
 sha1-file.c            | 268 +++++++++++++++++++++++++++++++++++++++++
 t/helper/test-sha512.c |  17 +++
 t/helper/test-tool.c   |   3 +
 t/helper/test-tool.h   |   3 +
 t/t0015-hash.sh        |  80 ++++++++++++
 10 files changed, 707 insertions(+), 4 deletions(-)
 create mode 100644 sha/sha512/gcrypt.h
 create mode 100644 sha/sha512/sha512.c
 create mode 100644 sha/sha512/sha512.h
 create mode 100644 t/helper/test-sha512.c

diff --git a/Makefile b/Makefile
index bac1b30b2f1f..2cd505b21ebb 100644
--- a/Makefile
+++ b/Makefile
@@ -183,6 +183,8 @@ all::
 #
 # Define BLK_SHA256 to use the built-in SHA-256 routines.
 #
+# Define BLK_SHA512 to use the built-in SHA-512 routines.
+#
 # Define GCRYPT_SHA256 to use the SHA-256 routines in libgcrypt.
 #
 # Define OPENSSL_SHA256 to use the SHA-256 routines in OpenSSL.
@@ -739,6 +741,7 @@ TEST_BUILTINS_OBJS += test-serve-v2.o
 TEST_BUILTINS_OBJS += test-sha1.o
 TEST_BUILTINS_OBJS += test-sha1-array.o
 TEST_BUILTINS_OBJS += test-sha256.o
+TEST_BUILTINS_OBJS += test-sha512.o
 TEST_BUILTINS_OBJS += test-sigchain.o
 TEST_BUILTINS_OBJS += test-strcmp-offset.o
 TEST_BUILTINS_OBJS += test-string-list.o
@@ -1712,6 +1715,14 @@ else
 endif
 endif
 
+ifdef GCRYPT_SHA512
+	BASIC_CFLAGS += -DSHA512_GCRYPT
+	EXTLIBS += -lgcrypt
+else
+	LIB_OBJS += sha/sha512/sha512.o
+	BASIC_CFLAGS += -DSHA512_BLK
+endif
+
 ifdef SHA1_MAX_BLOCK_SIZE
 	LIB_OBJS += compat/sha1-chunked.o
 	BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)"
@@ -2784,6 +2795,9 @@ EXCEPT_HDRS := $(GEN_HDRS) compat/% xdiff/%
 ifndef GCRYPT_SHA256
 	EXCEPT_HDRS += sha/sha256/gcrypt.h
 endif
+ifndef GCRYPT_SHA512
+	EXCEPT_HDRS += sha/sha512/gcrypt.h
+endif
 CHK_HDRS = $(filter-out $(EXCEPT_HDRS),$(LIB_H))
 HCO = $(patsubst %.h,%.hco,$(CHK_HDRS))
 HCC = $(HCO:hco=hcc)
diff --git a/hash.h b/hash.h
index f1b941218dc8..ea96fccce0c8 100644
--- a/hash.h
+++ b/hash.h
@@ -23,6 +23,12 @@
 #include "sha/sha256/sha256.h"
 #endif
 
+#if defined(SHA512_GCRYPT)
+#include "sha/sha512/gcrypt.h"
+#else
+#include "sha/sha512/sha512.h"
+#endif
+
 #ifndef platform_SHA_CTX
 /*
  * platform's underlying implementation of SHA-1; could be OpenSSL,
@@ -54,6 +60,13 @@
 #define git_SHA256_Update	platform_SHA256_Update
 #define git_SHA256_Final	platform_SHA256_Final
 
+#define git_SHA512_CTX		platform_SHA512_CTX
+#define git_SHA512_Init		platform_SHA512_Init
+#define git_SHA512_224_Init	platform_SHA512_224_Init
+#define git_SHA512_256_Init	platform_SHA512_256_Init
+#define git_SHA512_Update	platform_SHA512_Update
+#define git_SHA512_Final	platform_SHA512_Final
+
 #ifdef SHA1_MAX_BLOCK_SIZE
 #include "compat/sha1-chunked.h"
 #undef git_SHA1_Update
@@ -74,13 +87,20 @@
 #define GIT_HASH_SHA1 1
 /* SHA-256  */
 #define GIT_HASH_SHA256 2
+/* SHA-512  */
+#define GIT_HASH_SHA512 3
+/* SHA-512-224  */
+#define GIT_HASH_SHA512_224 4
+/* SHA-512-256  */
+#define GIT_HASH_SHA512_256 5
 /* Number of algorithms supported (including unknown). */
-#define GIT_HASH_NALGOS (GIT_HASH_SHA256 + 1)
+#define GIT_HASH_NALGOS (GIT_HASH_SHA512_256 + 1)
 
 /* A suitably aligned type for stack allocations of hash contexts. */
 union git_hash_ctx {
 	git_SHA_CTX sha1;
 	git_SHA256_CTX sha256;
+	git_SHA512_CTX sha512;
 };
 typedef union git_hash_ctx git_hash_ctx;
 
@@ -151,11 +171,29 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
 /* The block size of SHA-256. */
 #define GIT_SHA256_BLKSZ 64
 
+/* The length in bytes and in hex digits of an object name (SHA-512 value). */
+#define GIT_SHA512_RAWSZ 64
+#define GIT_SHA512_HEXSZ (2 * GIT_SHA512_RAWSZ)
+/* The block size of SHA-512. */
+#define GIT_SHA512_BLKSZ 128
+
+/* The length in bytes and in hex digits of an object name (SHA-512-224 value). */
+#define GIT_SHA512_224_RAWSZ 28
+#define GIT_SHA512_224_HEXSZ (2 * GIT_SHA512_224_RAWSZ)
+/* The block size of SHA-512-224. */
+#define GIT_SHA512_224_BLKSZ 128
+
+/* The length in bytes and in hex digits of an object name (SHA-512-256 value). */
+#define GIT_SHA512_256_RAWSZ 32
+#define GIT_SHA512_256_HEXSZ (2 * GIT_SHA512_256_RAWSZ)
+/* The block size of SHA-512-256. */
+#define GIT_SHA512_256_BLKSZ 128
+
 /* The length in byte and in hex digits of the largest possible hash value. */
-#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
-#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
+#define GIT_MAX_RAWSZ GIT_SHA512_RAWSZ
+#define GIT_MAX_HEXSZ GIT_SHA512_HEXSZ
 /* The largest possible block size for any supported hash. */
-#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
+#define GIT_MAX_BLKSZ GIT_SHA512_BLKSZ
 
 struct object_id {
 	unsigned char hash[GIT_MAX_RAWSZ];
diff --git a/sha/sha512/gcrypt.h b/sha/sha512/gcrypt.h
new file mode 100644
index 000000000000..fdc0097d0777
--- /dev/null
+++ b/sha/sha512/gcrypt.h
@@ -0,0 +1,43 @@
+#ifndef SHA512_GCRYPT_H
+#define SHA512_GCRYPT_H
+
+#include <gcrypt.h>
+
+#define SHA512_DIGEST_SIZE 64
+
+typedef gcry_md_hd_t gcrypt_SHA512_CTX;
+
+inline void gcrypt_SHA512_Init(gcrypt_SHA512_CTX *ctx)
+{
+	gcry_md_open(ctx, GCRY_MD_SHA512, 0);
+}
+
+inline void gcrypt_SHA512_224_Init(gcrypt_SHA512_CTX *ctx)
+{
+	gcry_md_open(ctx, GCRY_MD_SHA512_224, 0);
+}
+
+inline void gcrypt_SHA512_256_Init(gcrypt_SHA512_CTX *ctx)
+{
+	gcry_md_open(ctx, GCRY_MD_SHA512_256, 0);
+}
+
+inline void gcrypt_SHA512_Update(gcrypt_SHA512_CTX *ctx, const void *data, size_t len)
+{
+	gcry_md_write(*ctx, data, len);
+}
+
+inline void gcrypt_SHA512_Final(unsigned char *digest, gcrypt_SHA512_CTX *ctx)
+{
+	int algo = gcry_md_get_algo(ctx);
+	unsigned int dlen = gcry_md_get_algo_dlen(algo);
+	memcpy(digest, gcry_md_read(*ctx, algo), dlen);
+}
+
+#define platform_SHA512_CTX gcrypt_SHA512_CTX
+#define platform_SHA512_Init gcrypt_SHA512_Init
+#define platform_SHA512_256_Init gcrypt_SHA512_256_Init
+#define platform_SHA512_Update gcrypt_SHA512_Update
+#define platform_SHA512_Final gcrypt_SHA512_Final
+
+#endif
diff --git a/sha/sha512/sha512.c b/sha/sha512/sha512.c
new file mode 100644
index 000000000000..8c1955627648
--- /dev/null
+++ b/sha/sha512/sha512.c
@@ -0,0 +1,206 @@
+#include "git-compat-util.h"
+#include "./sha512.h"
+
+static const uint64_t SHA_512_K[80] = {
+	0x428a2f98d728ae22ull, 0x7137449123ef65cdull,
+	0xb5c0fbcfec4d3b2full, 0xe9b5dba58189dbbcull,
+	0x3956c25bf348b538ull, 0x59f111f1b605d019ull,
+	0x923f82a4af194f9bull, 0xab1c5ed5da6d8118ull,
+	0xd807aa98a3030242ull, 0x12835b0145706fbeull,
+	0x243185be4ee4b28cull, 0x550c7dc3d5ffb4e2ull,
+	0x72be5d74f27b896full, 0x80deb1fe3b1696b1ull,
+	0x9bdc06a725c71235ull, 0xc19bf174cf692694ull,
+	0xe49b69c19ef14ad2ull, 0xefbe4786384f25e3ull,
+	0x0fc19dc68b8cd5b5ull, 0x240ca1cc77ac9c65ull,
+	0x2de92c6f592b0275ull, 0x4a7484aa6ea6e483ull,
+	0x5cb0a9dcbd41fbd4ull, 0x76f988da831153b5ull,
+	0x983e5152ee66dfabull, 0xa831c66d2db43210ull,
+	0xb00327c898fb213full, 0xbf597fc7beef0ee4ull,
+	0xc6e00bf33da88fc2ull, 0xd5a79147930aa725ull,
+	0x06ca6351e003826full, 0x142929670a0e6e70ull,
+	0x27b70a8546d22ffcull, 0x2e1b21385c26c926ull,
+	0x4d2c6dfc5ac42aedull, 0x53380d139d95b3dfull,
+	0x650a73548baf63deull, 0x766a0abb3c77b2a8ull,
+	0x81c2c92e47edaee6ull, 0x92722c851482353bull,
+	0xa2bfe8a14cf10364ull, 0xa81a664bbc423001ull,
+	0xc24b8b70d0f89791ull, 0xc76c51a30654be30ull,
+	0xd192e819d6ef5218ull, 0xd69906245565a910ull,
+	0xf40e35855771202aull, 0x106aa07032bbd1b8ull,
+	0x19a4c116b8d2d0c8ull, 0x1e376c085141ab53ull,
+	0x2748774cdf8eeb99ull, 0x34b0bcb5e19b48a8ull,
+	0x391c0cb3c5c95a63ull, 0x4ed8aa4ae3418acbull,
+	0x5b9cca4f7763e373ull, 0x682e6ff3d6b2b8a3ull,
+	0x748f82ee5defb2fcull, 0x78a5636f43172f60ull,
+	0x84c87814a1f0ab72ull, 0x8cc702081a6439ecull,
+	0x90befffa23631e28ull, 0xa4506cebde82bde9ull,
+	0xbef9a3f7b2c67915ull, 0xc67178f2e372532bull,
+	0xca273eceea26619cull, 0xd186b8c721c0c207ull,
+	0xeada7dd6cde0eb1eull, 0xf57d4f7fee6ed178ull,
+	0x06f067aa72176fbaull, 0x0a637dc5a2c898a6ull,
+	0x113f9804bef90daeull, 0x1b710b35131c471bull,
+	0x28db77f523047d84ull, 0x32caab7b40c72493ull,
+	0x3c9ebe0a15c9bebcull, 0x431d67c49c100d4cull,
+	0x4cc5d4becb3e42b6ull, 0x597f299cfc657e2aull,
+	0x5fcb6fab3ad6faecull, 0x6c44198c4a475817ull
+};
+
+void blk_SHA512_224_Init(blk_SHA512_CTX *ctx)
+{
+	ctx->size = 0;
+	ctx->digestlen = blk_SHA512_224_HASHSIZE;
+	ctx->state[0] = 0x8c3d37c819544da2ull;
+	ctx->state[1] = 0x73e1996689dcd4d6ull;
+	ctx->state[2] = 0x1dfab7ae32ff9c82ull;
+	ctx->state[3] = 0x679dd514582f9fcfull;
+	ctx->state[4] = 0x0f6d2b697bd44da8ull;
+	ctx->state[5] = 0x77e36f7304c48942ull;
+	ctx->state[6] = 0x3f9d85a86a1d36c8ull;
+	ctx->state[7] = 0x1112e6ad91d692a1ull;
+}
+
+void blk_SHA512_256_Init(blk_SHA512_CTX *ctx)
+{
+	ctx->size = 0;
+	ctx->digestlen = blk_SHA512_256_HASHSIZE;
+	ctx->state[0] = 0x22312194fc2bf72cull;
+	ctx->state[1] = 0x9f555fa3c84c64c2ull;
+	ctx->state[2] = 0x2393b86b6f53b151ull;
+	ctx->state[3] = 0x963877195940eabdull;
+	ctx->state[4] = 0x96283ee2a88effe3ull;
+	ctx->state[5] = 0xbe5e1e2553863992ull;
+	ctx->state[6] = 0x2b0199fc2c85b8aaull;
+	ctx->state[7] = 0x0eb72ddc81c52ca2ull;
+}
+
+void blk_SHA512_Init(blk_SHA512_CTX *ctx)
+{
+	ctx->size = 0;
+	ctx->digestlen = blk_SHA512_HASHSIZE;
+	ctx->state[0] = 0x6a09e667f3bcc908ull;
+	ctx->state[1] = 0xbb67ae8584caa73bull;
+	ctx->state[2] = 0x3c6ef372fe94f82bull;
+	ctx->state[3] = 0xa54ff53a5f1d36f1ull;
+	ctx->state[4] = 0x510e527fade682d1ull;
+	ctx->state[5] = 0x9b05688c2b3e6c1full;
+	ctx->state[6] = 0x1f83d9abfb41bd6bull;
+	ctx->state[7] = 0x5be0cd19137e2179ull;
+}
+
+static inline uint64_t ror(uint64_t x, unsigned n)
+{
+	return (x >> n) | (x << (64 - n));
+}
+
+static inline uint64_t ch(uint64_t x, uint64_t y, uint64_t z)
+{
+	return z ^ (x & (y ^ z));
+}
+
+static inline uint64_t maj(uint64_t x, uint64_t y, uint64_t z)
+{
+	return ((x | y) & z) | (x & y);
+}
+
+static inline uint64_t sigma0(uint64_t x)
+{
+	return ror(x, 28) ^ ror(x, 34) ^ ror(x, 39);
+}
+
+static inline uint64_t sigma1(uint64_t x)
+{
+	return ror(x, 14) ^ ror(x, 18) ^ ror(x, 41);
+}
+
+static inline uint64_t gamma0(uint64_t x)
+{
+	return ror(x, 1) ^ ror(x, 8) ^ (x >> 7);
+}
+
+static inline uint64_t gamma1(uint64_t x)
+{
+	return ror(x, 19) ^ ror(x, 61) ^ (x >> 6);
+}
+
+static void blk_SHA512_Transform(blk_SHA512_CTX *ctx, const unsigned char *buf)
+{
+	uint64_t S[8], W[80], t0, t1;
+	int i;
+
+	/* copy state into S */
+	for (i = 0; i < 8; i++)
+		S[i] = ctx->state[i];
+
+	/* copy the state into 1024-bits into W[0..15] */
+	for (i=0; i<16; i++, buf += sizeof(uint64_t)) {
+		W[i] = get_be64(buf);
+	}
+
+	/* fill W[16..80] */
+	for (; i<80; i++) {
+		W[i] = gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16];
+	}
+
+	/* compute SHA rounds */
+	for (i=0; i<80; i++) {
+		t0 = W[i] + S[7] + sigma1(S[4]) + ch(S[4], S[5], S[6]) + SHA_512_K[i];
+		t1 = maj(S[0], S[1], S[2]) + sigma0(S[0]);
+		S[7] = S[6];
+		S[6] = S[5];
+		S[5] = S[4];
+		S[4] = S[3] + t0;
+		S[3] = S[2];
+		S[2] = S[1];
+		S[1] = S[0];
+		S[0] = t0 + t1;
+	}
+
+	for (i = 0; i < 8; i++)
+		ctx->state[i] += S[i];
+}
+
+void blk_SHA512_Update(blk_SHA512_CTX *ctx, const void *data, size_t len)
+{
+	unsigned int len_buf = ctx->size & 127;
+
+	ctx->size += len;
+
+	/* Read the data into buf and process blocks as they get full */
+	if (len_buf) {
+		unsigned int left = 128 - len_buf;
+		if (len < left)
+			left = len;
+		memcpy(len_buf + ctx->buf, data, left);
+		len_buf = (len_buf + left) & 127;
+		len -= left;
+		data = ((const char *)data + left);
+		if (len_buf)
+			return;
+		blk_SHA512_Transform(ctx, ctx->buf);
+	}
+	while (len >= 128) {
+		blk_SHA512_Transform(ctx, data);
+		data = ((const char *)data + 128);
+		len -= 128;
+	}
+	if (len)
+		memcpy(ctx->buf, data, len);
+}
+
+void blk_SHA512_Final(uint8_t *digest, blk_SHA512_CTX *ctx)
+{
+	static const unsigned char pad[128] = { 0x80 };
+	unsigned int padlen[2];
+	int i;
+
+	/* Pad with a binary 1 (ie 0x80), then zeroes, then length */
+	padlen[0] = htonl((uint32_t)(ctx->size >> 29));
+	padlen[1] = htonl((uint32_t)(ctx->size << 3));
+
+	i = ctx->size & 127;
+	blk_SHA512_Update(ctx, pad, 1 + (127 & (119 - i)));
+	blk_SHA512_Update(ctx, padlen, 8);
+
+	/* copy output */
+	for (i = 0; i < 8; i++, digest += sizeof(uint64_t))
+		put_be64(digest, ctx->state[i]);
+}
diff --git a/sha/sha512/sha512.h b/sha/sha512/sha512.h
new file mode 100644
index 000000000000..bc063f0af868
--- /dev/null
+++ b/sha/sha512/sha512.h
@@ -0,0 +1,31 @@
+#ifndef SHA512_BLOCK_SHA512_H
+#define SHA512_BLOCK_SHA512_H
+
+#define blk_SHA512_BLKSIZE 128
+#define blk_SHA512_224_HASHSIZE 28
+#define blk_SHA512_256_HASHSIZE 32
+#define blk_SHA512_HASHSIZE 64
+
+struct blk_SHA512_CTX {
+	uint64_t state[8];
+	uint64_t size;
+	uint64_t digestlen;
+	uint8_t buf[blk_SHA512_BLKSIZE];
+};
+
+typedef struct blk_SHA512_CTX blk_SHA512_CTX;
+
+void blk_SHA512_Init(blk_SHA512_CTX *ctx);
+void blk_SHA512_224_Init(blk_SHA512_CTX *ctx);
+void blk_SHA512_256_Init(blk_SHA512_CTX *ctx);
+void blk_SHA512_Update(blk_SHA512_CTX *ctx, const void *data, size_t len);
+void blk_SHA512_Final(unsigned char *digest, blk_SHA512_CTX *ctx);
+
+#define platform_SHA512_CTX blk_SHA512_CTX
+#define platform_SHA512_Init blk_SHA512_Init
+#define platform_SHA512_224_Init blk_SHA512_224_Init
+#define platform_SHA512_256_Init blk_SHA512_256_Init
+#define platform_SHA512_Update blk_SHA512_Update
+#define platform_SHA512_Final blk_SHA512_Final
+
+#endif
diff --git a/sha1-file.c b/sha1-file.c
index 188de57634bb..1f5b835a9f24 100644
--- a/sha1-file.c
+++ b/sha1-file.c
@@ -45,6 +45,46 @@
 	"\x04\xd4\x5d\x8d\x85\xef\xa9\xb0\x57\xb5" \
 	"\x3b\x14\xb4\xb9\xb9\x39\xdd\x74\xde\xcc" \
 	"\x53\x21"
+#define EMPTY_TREE_SHA512_224_BIN_LITERAL \
+	"\xaa\xff\x3a\xb0\x67\xb1\x51\xd0\xbc\x31" \
+	"\x30\x27\x7d\x64\xa1\x1e\xb2\x57\xe0\xfe" \
+	"\xca\x74\xe0\xdc\xb7\xe3\x83\x03"
+#define EMPTY_TREE_SHA512_256_BIN_LITERAL \
+	"\x2c\xfe\x78\xf8\xea\x2f\xa9\xd2\x19\x37" \
+	"\x48\x68\xe7\xaa\x1f\xe4\x91\x62\x2b\xcb" \
+	"\x58\x15\xdc\xf3\xad\x12\xf3\x08\xbe\x79" \
+	"\x59\xdb"
+#define EMPTY_TREE_SHA512_BIN_LITERAL \
+	"\xd5\x1f\xd9\x2f\xdd\x8b\x29\xd0\x8f\x5c" \
+	"\xba\x26\x1a\xbb\x22\x15\x29\xe6\xff\xb1" \
+	"\x26\x4c\x51\x1b\xe2\x16\xd2\xf5\x30\x6e" \
+	"\xcd\xcc\x38\xe2\x39\x2d\xe4\xf6\x2c\x74" \
+	"\x56\x07\xa9\x76\x80\xfc\x7c\xcb\xbe\x73" \
+	"\x04\x4d\xfc\x03\xd8\x9e\xd9\x5b\xa5\x49" \
+	"\x67\x90\x91\x95"
+#define EMPTY_TREE_SHA3_224_BIN_LITERAL \
+	"\x1e\x04\xf2\x3d\xe0\xb2\xb7\xd1\xb8\x5e" \
+	"\x67\x68\xfa\x99\x7a\x99\xbd\x01\x19\xde" \
+	"\xc8\x15\x8a\xe0\xad\x07\xe1\x83"
+#define EMPTY_TREE_SHA3_256_BIN_LITERAL \
+	"\x30\x21\x1e\xd4\x85\xc9\x12\xe5\xbc\x28" \
+	"\x5b\xd0\xbd\x89\x59\xdd\xbf\xb5\x87\x5c" \
+	"\xaf\xb0\xae\x28\xe0\xab\xfa\x10\x77\xb2" \
+	"\xb2\x14"
+#define EMPTY_TREE_SHA3_384_BIN_LITERAL \
+	"\x92\xe9\x9a\xe9\x28\x1a\x89\xdc\x33\x2c" \
+	"\x9c\xe8\xf2\x83\x1d\xb5\x0e\xcc\x54\x78" \
+	"\x4d\x51\xc3\xeb\xd5\xc1\x15\x1e\x8f\xd6" \
+	"\x03\xfb\x40\x8a\xbb\xbb\x9d\xcf\x57\x13" \
+	"\xed\x21\x56\x67\x89\xce\x80\x59"
+#define EMPTY_TREE_SHA3_512_BIN_LITERAL \
+	"\x8f\x86\xcb\x67\xce\x0a\x8b\xc8\x65\xb3" \
+	"\x00\x73\x3c\x27\xda\xde\x0e\xa8\xfe\x66" \
+	"\x29\x9b\x4b\xc6\x36\x8e\xc8\x4f\x53\x13" \
+	"\x4c\x36\x7c\x66\xf0\xe3\x37\x62\x61\xab" \
+	"\x5a\x86\xd7\x22\xad\x0d\x98\x39\x1a\x3c" \
+	"\x1c\x47\x2d\x67\x91\xda\x46\x4a\x78\x36" \
+	"\x00\x6d\xe1\x2c"
 
 #define EMPTY_BLOB_SHA1_BIN_LITERAL \
 	"\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
@@ -54,6 +94,46 @@
 	"\x67\xe3\xb1\xe9\xa7\xdc\xda\x11\x85\x43" \
 	"\x6f\xe1\x41\xf7\x74\x91\x20\xa3\x03\x72" \
 	"\x18\x13"
+#define EMPTY_BLOB_SHA512_224_BIN_LITERAL \
+	"\xa8\x6d\x3c\x63\x33\x98\x60\x44\x56\x07" \
+	"\xd6\xcf\xd3\x55\x12\x92\xa6\xfb\x04\x9f" \
+	"\x0f\xaa\x22\x2a\x7c\x10\x02\x7b"
+#define EMPTY_BLOB_SHA512_256_BIN_LITERAL \
+	"\x65\x76\x66\x8d\x3a\xcf\x02\x2c\x9c\x77" \
+	"\x92\x0c\x83\x49\xed\x6c\xcd\x8f\xc5\x96" \
+	"\x84\x5e\x87\xc3\x8b\x9e\x74\x90\x16\xc9" \
+	"\x84\xb3"
+#define EMPTY_BLOB_SHA512_BIN_LITERAL \
+	"\xba\x4d\x0b\xb3\xec\x89\x0f\xdc\x47\xa1" \
+	"\x0d\xf5\x3a\x59\x1a\x79\x85\x22\x37\xd5" \
+	"\xe6\x35\x45\x5d\xa9\x0a\x37\x42\xd7\x48" \
+	"\x27\x08\xb5\x7d\xe2\xff\xab\xc7\x58\x1f" \
+	"\x58\x1e\xe8\x07\x5f\xba\xb3\x47\x62\x70" \
+	"\x94\x2c\xdf\x87\xfa\x7d\xd6\x89\x5d\xaa" \
+	"\x65\x09\x89\x6c"
+#define EMPTY_BLOB_SHA3_224_BIN_LITERAL \
+	"\xf1\xe7\x29\x35\xac\x5c\x52\xd5\xc0\x9b" \
+	"\x40\x88\x42\xe2\x07\xc4\x2e\x54\x34\x42" \
+	"\x40\x07\x36\x4f\xdb\x46\x80\x63"
+#define EMPTY_BLOB_SHA3_256_BIN_LITERAL \
+	"\x5a\xad\xde\x7d\x8c\xa5\xb9\xb3\x52\xc2" \
+	"\x50\xce\x9b\x79\x9f\x5d\x81\x88\x93\xfe" \
+	"\x89\xdc\x52\xb4\x9f\x43\x8c\x8a\x9b\xa0" \
+	"\xa5\x45"
+#define EMPTY_BLOB_SHA3_384_BIN_LITERAL \
+	"\xa5\x3e\x08\x8a\xbe\x90\x8d\x8c\x94\x58" \
+	"\xa8\xba\x95\x56\x90\xc4\x17\xf7\x68\x03" \
+	"\x1e\xcf\x15\x6a\x16\x62\x44\x1f\xae\xda" \
+	"\x50\x2e\x83\x8f\x26\x60\x16\x4b\x61\xa7" \
+	"\x8b\x15\xac\x75\xe0\xf8\xde\xd4"
+#define EMPTY_BLOB_SHA3_512_BIN_LITERAL \
+	"\x43\x53\xa5\x0d\x0d\x3d\x8e\xdd\x23\x17" \
+	"\x63\xfb\x01\x02\x11\x62\x86\xaa\x6d\x76" \
+	"\x0a\x77\x21\x33\xe3\x2c\x12\x4a\x99\x8a" \
+	"\x19\x46\x7d\x78\x90\x64\xdd\x76\x3e\x57" \
+	"\xb5\x47\xff\x3a\x31\x88\x2d\xa3\xd2\x03" \
+	"\x13\x78\xcf\xe0\xfa\x57\x74\xc1\x2e\xea" \
+	"\x51\x05\x5a\x51"
 
 const struct object_id null_oid;
 static const struct object_id empty_tree_oid = {
@@ -68,6 +148,48 @@ static const struct object_id empty_tree_oid_sha256 = {
 static const struct object_id empty_blob_oid_sha256 = {
 	EMPTY_BLOB_SHA256_BIN_LITERAL
 };
+static const struct object_id empty_tree_oid_sha512 = {
+	EMPTY_TREE_SHA512_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha512 = {
+	EMPTY_BLOB_SHA512_BIN_LITERAL
+};
+static const struct object_id empty_tree_oid_sha512_224 = {
+	EMPTY_TREE_SHA512_224_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha512_224 = {
+	EMPTY_BLOB_SHA512_224_BIN_LITERAL
+};
+static const struct object_id empty_tree_oid_sha512_256 = {
+	EMPTY_TREE_SHA512_256_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha512_256 = {
+	EMPTY_BLOB_SHA512_256_BIN_LITERAL
+};
+static const struct object_id empty_tree_oid_sha3_224 = {
+	EMPTY_TREE_SHA3_224_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha3_224 = {
+	EMPTY_BLOB_SHA3_224_BIN_LITERAL
+};
+static const struct object_id empty_tree_oid_sha3_256 = {
+	EMPTY_TREE_SHA3_256_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha3_256 = {
+	EMPTY_BLOB_SHA3_256_BIN_LITERAL
+};
+static const struct object_id empty_tree_oid_sha3_384 = {
+	EMPTY_TREE_SHA3_384_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha3_384 = {
+	EMPTY_BLOB_SHA3_384_BIN_LITERAL
+};
+static const struct object_id empty_tree_oid_sha3_512 = {
+	EMPTY_TREE_SHA3_512_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha3_512 = {
+	EMPTY_BLOB_SHA3_512_BIN_LITERAL
+};
 
 static void git_hash_sha1_init(git_hash_ctx *ctx)
 {
@@ -100,6 +222,61 @@ static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx)
 	git_SHA256_Final(hash, &ctx->sha256);
 }
 
+static void git_hash_sha512_init(git_hash_ctx *ctx)
+{
+	git_SHA512_Init(&ctx->sha512);
+}
+
+static void git_hash_sha512_224_init(git_hash_ctx *ctx)
+{
+	git_SHA512_224_Init(&ctx->sha512);
+}
+
+static void git_hash_sha512_256_init(git_hash_ctx *ctx)
+{
+	git_SHA512_256_Init(&ctx->sha512);
+}
+
+static void git_hash_sha512_update(git_hash_ctx *ctx, const void *data, size_t len)
+{
+	git_SHA512_Update(&ctx->sha512, data, len);
+}
+
+static void git_hash_sha512_final(unsigned char *hash, git_hash_ctx *ctx)
+{
+	git_SHA512_Final(hash, &ctx->sha512);
+}
+
+static void git_hash_sha3_224_init(git_hash_ctx *ctx)
+{
+	git_SHA3_224_Init(&ctx->sha3);
+}
+
+static void git_hash_sha3_256_init(git_hash_ctx *ctx)
+{
+	git_SHA3_256_Init(&ctx->sha3);
+}
+
+static void git_hash_sha3_384_init(git_hash_ctx *ctx)
+{
+	git_SHA3_384_Init(&ctx->sha3);
+}
+
+static void git_hash_sha3_512_init(git_hash_ctx *ctx)
+{
+	git_SHA3_512_Init(&ctx->sha3);
+}
+
+static void git_hash_sha3_update(git_hash_ctx *ctx, const void *data, size_t len)
+{
+	git_SHA3_Update(&ctx->sha3, data, len);
+}
+
+static void git_hash_sha3_final(unsigned char *hash, git_hash_ctx *ctx)
+{
+	git_SHA3_Final(hash, &ctx->sha3);
+}
+
 static void git_hash_unknown_init(git_hash_ctx *ctx)
 {
 	BUG("trying to init unknown hash");
@@ -153,6 +330,97 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
 		git_hash_sha256_final,
 		&empty_tree_oid_sha256,
 		&empty_blob_oid_sha256,
+	},
+	{
+		"sha512",
+		/* "s512", big-endian */
+		0x73353132,
+		GIT_SHA512_RAWSZ,
+		GIT_SHA512_HEXSZ,
+		GIT_SHA512_BLKSZ,
+		git_hash_sha512_init,
+		git_hash_sha512_update,
+		git_hash_sha512_final,
+		&empty_tree_oid_sha512,
+		&empty_blob_oid_sha512,
+	},
+	{
+		"sha512/224",
+		/* "s226", big-endian */
+		0x73323236,
+		GIT_SHA512_224_RAWSZ,
+		GIT_SHA512_224_HEXSZ,
+		GIT_SHA512_224_BLKSZ,
+		git_hash_sha512_224_init,
+		git_hash_sha512_update,
+		git_hash_sha512_final,
+		&empty_tree_oid_sha512_224,
+		&empty_blob_oid_sha512_224,
+	},
+	{
+		"sha512/256",
+		/* "s228", big-endian */
+		0x73323238,
+		GIT_SHA512_256_RAWSZ,
+		GIT_SHA512_256_HEXSZ,
+		GIT_SHA512_256_BLKSZ,
+		git_hash_sha512_256_init,
+		git_hash_sha512_update,
+		git_hash_sha512_final,
+		&empty_tree_oid_sha512_256,
+		&empty_blob_oid_sha512_256,
+	},
+	{
+		"sha3-224",
+		/* "s388", big-endian */
+		0x73333838,
+		GIT_SHA3_224_RAWSZ,
+		GIT_SHA3_224_HEXSZ,
+		GIT_SHA3_224_BLKSZ,
+		git_hash_sha3_224_init,
+		git_hash_sha3_update,
+		git_hash_sha3_final,
+		&empty_tree_oid_sha3_224,
+		&empty_blob_oid_sha3_224,
+	},
+	{
+		"sha3-256",
+		/* "s398", big-endian */
+		0x73333938,
+		GIT_SHA3_256_RAWSZ,
+		GIT_SHA3_256_HEXSZ,
+		GIT_SHA3_256_BLKSZ,
+		git_hash_sha3_256_init,
+		git_hash_sha3_update,
+		git_hash_sha3_final,
+		&empty_tree_oid_sha3_256,
+		&empty_blob_oid_sha3_256,
+	},
+	{
+		"sha3-384",
+		/* "s3a8", big-endian */
+		0x73336138,
+		GIT_SHA3_384_RAWSZ,
+		GIT_SHA3_384_HEXSZ,
+		GIT_SHA3_384_BLKSZ,
+		git_hash_sha3_384_init,
+		git_hash_sha3_update,
+		git_hash_sha3_final,
+		&empty_tree_oid_sha3_384,
+		&empty_blob_oid_sha3_384,
+	},
+	{
+		"sha3-512",
+		/* "s3b8", big-endian */
+		0x73336238,
+		GIT_SHA3_512_RAWSZ,
+		GIT_SHA3_512_HEXSZ,
+		GIT_SHA3_512_BLKSZ,
+		git_hash_sha3_512_init,
+		git_hash_sha3_update,
+		git_hash_sha3_final,
+		&empty_tree_oid_sha3_512,
+		&empty_blob_oid_sha3_512,
 	}
 };
 
diff --git a/t/helper/test-sha512.c b/t/helper/test-sha512.c
new file mode 100644
index 000000000000..c80941a2a595
--- /dev/null
+++ b/t/helper/test-sha512.c
@@ -0,0 +1,17 @@
+#include "test-tool.h"
+#include "cache.h"
+
+int cmd__sha512(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA512);
+}
+
+int cmd__sha512_224(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA512_224);
+}
+
+int cmd__sha512_256(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA512_256);
+}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index f20989d4497b..47deff9c6ef4 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -57,6 +57,9 @@ static struct test_cmd cmds[] = {
 	{ "sha1", cmd__sha1 },
 	{ "sha1-array", cmd__sha1_array },
 	{ "sha256", cmd__sha256 },
+	{ "sha512", cmd__sha512 },
+	{ "sha512-224", cmd__sha512_224 },
+	{ "sha512-256", cmd__sha512_256 },
 	{ "sigchain", cmd__sigchain },
 	{ "strcmp-offset", cmd__strcmp_offset },
 	{ "string-list", cmd__string_list },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 8ed2af71d1b2..927540dff7dd 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -47,6 +47,9 @@ int cmd__serve_v2(int argc, const char **argv);
 int cmd__sha1(int argc, const char **argv);
 int cmd__sha1_array(int argc, const char **argv);
 int cmd__sha256(int argc, const char **argv);
+int cmd__sha512(int argc, const char **argv);
+int cmd__sha512_224(int argc, const char **argv);
+int cmd__sha512_256(int argc, const char **argv);
 int cmd__sigchain(int argc, const char **argv);
 int cmd__strcmp_offset(int argc, const char **argv);
 int cmd__string_list(int argc, const char **argv);
diff --git a/t/t0015-hash.sh b/t/t0015-hash.sh
index 291e9061f39d..4735befe1c72 100755
--- a/t/t0015-hash.sh
+++ b/t/t0015-hash.sh
@@ -52,4 +52,84 @@ test_expect_success 'test basic SHA-256 hash values' '
 	grep 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321 actual
 '
 
+test_expect_success 'test basic SHA-512/224 hash values' '
+	test-tool sha512-224 </dev/null >actual &&
+	grep 6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4 actual &&
+	printf "a" | test-tool sha512-224 >actual &&
+	grep d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327 actual &&
+	printf "abc" | test-tool sha512-224 >actual &&
+	grep 4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa actual &&
+	printf "message digest" | test-tool sha512-224 >actual &&
+	grep ad1a4db188fe57064f4f24609d2a83cd0afb9b398eb2fcaeaae2c564 actual &&
+	printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha512-224 >actual &&
+	grep ff83148aa07ec30655c1b40aff86141c0215fe2a54f767d3f38743d8 actual &&
+	# Try to exercise the chunking code by turning autoflush on.
+	perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+		test-tool sha512-224 >actual &&
+	grep 37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287 actual &&
+	perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+		test-tool sha512-224 >actual &&
+	grep 6a312ce7c451ef28bf9ad33f5ce85ddf2d9f07097660160dbcb5c4c4 actual &&
+	printf "blob 0\0" | test-tool sha512-224 >actual &&
+	grep a86d3c63339860445607d6cfd3551292a6fb049f0faa222a7c10027b actual &&
+	printf "blob 3\0abc" | test-tool sha512-224 >actual &&
+	grep 9d6948b51bccf6b9814288d3e8cbca42f5e31b825ec613b23a45a546 actual &&
+	printf "tree 0\0" | test-tool sha512-224 >actual &&
+	grep aaff3ab067b151d0bc3130277d64a11eb257e0feca74e0dcb7e38303 actual
+'
+
+test_expect_success 'test basic SHA-512/256 hash values' '
+	test-tool sha512-256 </dev/null >actual &&
+	grep c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a actual &&
+	printf "a" | test-tool sha512-256 >actual &&
+	grep 455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8 actual &&
+	printf "abc" | test-tool sha512-256 >actual &&
+	grep 53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23 actual &&
+	printf "message digest" | test-tool sha512-256 >actual &&
+	grep 0cf471fd17ed69d990daf3433c89b16d63dec1bb9cb42a6094604ee5d7b4e9fb actual &&
+	printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha512-256 >actual &&
+	grep fc3189443f9c268f626aea08a756abe7b726b05f701cb08222312ccfd6710a26 actual &&
+	# Try to exercise the chunking code by turning autoflush on.
+	perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+		test-tool sha512-256 >actual &&
+	grep 9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21 actual &&
+	perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+		test-tool sha512-256 >actual &&
+	grep b8803f7dc283e57eeb6340a3ba9d9a2098125500008b5bfdfeeb6ddd0582d2b8 actual &&
+	printf "blob 0\0" | test-tool sha512-256 >actual &&
+	grep 6576668d3acf022c9c77920c8349ed6ccd8fc596845e87c38b9e749016c984b3 actual &&
+	printf "blob 3\0abc" | test-tool sha512-256 >actual &&
+	grep 815d5a4e692c971eea251f5e8d86b42953640027d8f1163d9f33adeb5e1f7a7a actual &&
+	printf "tree 0\0" | test-tool sha512-256 >actual &&
+	grep 2cfe78f8ea2fa9d219374868e7aa1fe491622bcb5815dcf3ad12f308be7959db actual
+
+'
+
+test_expect_success 'test basic SHA-512 hash values' '
+	test-tool sha512 </dev/null >actual &&
+	grep cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e actual &&
+	printf "a" | test-tool sha512 >actual &&
+	grep 1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75 actual &&
+	printf "abc" | test-tool sha512 >actual &&
+	grep ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f actual &&
+	printf "message digest" | test-tool sha512 >actual &&
+	grep 107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c actual &&
+	printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha512 >actual &&
+	grep 4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1 actual &&
+	# Try to exercise the chunking code by turning autoflush on.
+	perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+		test-tool sha512 >actual &&
+	grep e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b actual &&
+	perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+		test-tool sha512 >actual &&
+	grep daeddbe45570b154876086f66464a1a1ea6b623bd6bf53132a92f3326e0edb5cb8bf3eef58fe0b15c87526a226bd3242cad65f1f2025f1dbde0c30e41a9f8253 actual &&
+	printf "blob 0\0" | test-tool sha512 >actual &&
+	grep ba4d0bb3ec890fdc47a10df53a591a79852237d5e635455da90a3742d7482708b57de2ffabc7581f581ee8075fbab3476270942cdf87fa7dd6895daa6509896c actual &&
+	printf "blob 3\0abc" | test-tool sha512 >actual &&
+	grep 55abbe2a993e9d900dcd5e1315dbf5bc634af92500bf4242fd9c5bba38090ee043fc886018aab7fa7d855abf41162a1fcb49ef7bd56778fd6c0b9d1a7ba00a71 actual &&
+	printf "tree 0\0" | test-tool sha512 >actual &&
+	grep d51fd92fdd8b29d08f5cba261abb221529e6ffb1264c511be216d2f5306ecdcc38e2392de4f62c745607a97680fc7ccbbe73044dfc03d89ed95ba54967909195 actual
+
+'
+
 test_done
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/6] Add an implementation of the SHA-3 hash algorithm
  2019-12-22  6:48 [PATCH 0/6] Additional SHA implementations Michael Clark
  2019-12-22  6:48 ` [PATCH 1/6] Move all SHA algorithm variants into sha/ directory Michael Clark
  2019-12-22  6:48 ` [PATCH 2/6] Add an implementation of the SHA-512 hash algorithm Michael Clark
@ 2019-12-22  6:48 ` Michael Clark
  2019-12-22  6:48 ` [PATCH 4/6] Add an implementation of the SHA224 truncated " Michael Clark
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Michael Clark @ 2019-12-22  6:48 UTC (permalink / raw)
  To: git; +Cc: Michael Clark

- Add SHA3-224, SHA3-256, SHA3-384 and SHA3-512 hash algorithms
  derived from the Keccak SHA-3 submission to NIST (Round 3), 2011
  by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
- Add configuration machinery to select builtin impl or gcrypt.
- Add sha3-224, sha3-256, sha3-384 and sha3-512 commands to test-tool.
- Add sha3 hash tests to t/t0015-hash.sh
---
 Makefile             |   9 ++
 hash.h               |  49 +++++++-
 sha/sha3/gcrypt.h    |  53 +++++++++
 sha/sha3/sha3.c      | 271 +++++++++++++++++++++++++++++++++++++++++++
 sha/sha3/sha3.h      |  34 ++++++
 t/helper/test-sha3.c |  22 ++++
 t/helper/test-tool.c |   4 +
 t/helper/test-tool.h |   4 +
 t/t0015-hash.sh      | 108 +++++++++++++++++
 9 files changed, 553 insertions(+), 1 deletion(-)
 create mode 100644 sha/sha3/gcrypt.h
 create mode 100644 sha/sha3/sha3.c
 create mode 100644 sha/sha3/sha3.h
 create mode 100644 t/helper/test-sha3.c

diff --git a/Makefile b/Makefile
index 2cd505b21ebb..6bf9900291cb 100644
--- a/Makefile
+++ b/Makefile
@@ -742,6 +742,7 @@ TEST_BUILTINS_OBJS += test-sha1.o
 TEST_BUILTINS_OBJS += test-sha1-array.o
 TEST_BUILTINS_OBJS += test-sha256.o
 TEST_BUILTINS_OBJS += test-sha512.o
+TEST_BUILTINS_OBJS += test-sha3.o
 TEST_BUILTINS_OBJS += test-sigchain.o
 TEST_BUILTINS_OBJS += test-strcmp-offset.o
 TEST_BUILTINS_OBJS += test-string-list.o
@@ -1723,6 +1724,14 @@ else
 	BASIC_CFLAGS += -DSHA512_BLK
 endif
 
+ifdef GCRYPT_SHA3
+	BASIC_CFLAGS += -DSHA3_GCRYPT
+	EXTLIBS += -lgcrypt
+else
+	LIB_OBJS += sha/sha3/sha3.o
+	BASIC_CFLAGS += -DSHA3_BLK
+endif
+
 ifdef SHA1_MAX_BLOCK_SIZE
 	LIB_OBJS += compat/sha1-chunked.o
 	BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)"
diff --git a/hash.h b/hash.h
index ea96fccce0c8..4826de3c80d4 100644
--- a/hash.h
+++ b/hash.h
@@ -29,6 +29,12 @@
 #include "sha/sha512/sha512.h"
 #endif
 
+#if defined(SHA3_GCRYPT)
+#include "sha/sha3/gcrypt.h"
+#else
+#include "sha/sha3/sha3.h"
+#endif
+
 #ifndef platform_SHA_CTX
 /*
  * platform's underlying implementation of SHA-1; could be OpenSSL,
@@ -67,6 +73,14 @@
 #define git_SHA512_Update	platform_SHA512_Update
 #define git_SHA512_Final	platform_SHA512_Final
 
+#define git_SHA3_CTX 		platform_SHA3_CTX
+#define git_SHA3_224_Init 	platform_SHA3_224_Init
+#define git_SHA3_256_Init 	platform_SHA3_256_Init
+#define git_SHA3_384_Init 	platform_SHA3_384_Init
+#define git_SHA3_512_Init 	platform_SHA3_512_Init
+#define git_SHA3_Update 	platform_SHA3_Update
+#define git_SHA3_Final	 	platform_SHA3_Final
+
 #ifdef SHA1_MAX_BLOCK_SIZE
 #include "compat/sha1-chunked.h"
 #undef git_SHA1_Update
@@ -93,14 +107,23 @@
 #define GIT_HASH_SHA512_224 4
 /* SHA-512-256  */
 #define GIT_HASH_SHA512_256 5
+/* SHA-3-224 */
+#define GIT_HASH_SHA3_224 6
+/* SHA-3-256 */
+#define GIT_HASH_SHA3_256 7
+/* SHA-3-384 */
+#define GIT_HASH_SHA3_384 8
+/* SHA-3-512 */
+#define GIT_HASH_SHA3_512 9
 /* Number of algorithms supported (including unknown). */
-#define GIT_HASH_NALGOS (GIT_HASH_SHA512_256 + 1)
+#define GIT_HASH_NALGOS (GIT_HASH_SHA3_512 + 1)
 
 /* A suitably aligned type for stack allocations of hash contexts. */
 union git_hash_ctx {
 	git_SHA_CTX sha1;
 	git_SHA256_CTX sha256;
 	git_SHA512_CTX sha512;
+	git_SHA3_CTX sha3;
 };
 typedef union git_hash_ctx git_hash_ctx;
 
@@ -189,6 +212,30 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
 /* The block size of SHA-512-256. */
 #define GIT_SHA512_256_BLKSZ 128
 
+/* The length in bytes and in hex digits of an object name (SHA-3-224 value). */
+#define GIT_SHA3_224_RAWSZ 28
+#define GIT_SHA3_224_HEXSZ (2 * GIT_SHA3_224_RAWSZ)
+/* The block size of SHA-3-224. */
+#define GIT_SHA3_224_BLKSZ 128
+
+/* The length in bytes and in hex digits of an object name (SHA-3-256 value). */
+#define GIT_SHA3_256_RAWSZ 32
+#define GIT_SHA3_256_HEXSZ (2 * GIT_SHA3_256_RAWSZ)
+/* The block size of SHA-3-256. */
+#define GIT_SHA3_256_BLKSZ 128
+
+/* The length in bytes and in hex digits of an object name (SHA-3-384 value). */
+#define GIT_SHA3_384_RAWSZ 48
+#define GIT_SHA3_384_HEXSZ (2 * GIT_SHA3_384_RAWSZ)
+/* The block size of SHA-3-384. */
+#define GIT_SHA3_384_BLKSZ 128
+
+/* The length in bytes and in hex digits of an object name (SHA-3-512 value). */
+#define GIT_SHA3_512_RAWSZ 64
+#define GIT_SHA3_512_HEXSZ (2 * GIT_SHA3_512_RAWSZ)
+/* The block size of SHA-3-512. */
+#define GIT_SHA3_512_BLKSZ 128
+
 /* The length in byte and in hex digits of the largest possible hash value. */
 #define GIT_MAX_RAWSZ GIT_SHA512_RAWSZ
 #define GIT_MAX_HEXSZ GIT_SHA512_HEXSZ
diff --git a/sha/sha3/gcrypt.h b/sha/sha3/gcrypt.h
new file mode 100644
index 000000000000..47a1482d65bc
--- /dev/null
+++ b/sha/sha3/gcrypt.h
@@ -0,0 +1,53 @@
+#ifndef SHA3_GCRYPT_H
+#define SHA3_GCRYPT_H
+
+#include <gcrypt.h>
+
+#define SHA3_224_DIGEST_SIZE 28
+#define SHA3_256_DIGEST_SIZE 32
+#define SHA3_384_DIGEST_SIZE 48
+#define SHA3_512_DIGEST_SIZE 64
+
+typedef gcry_md_hd_t gcrypt_SHA3_CTX;
+
+inline void gcrypt_SHA3_224_Init(gcrypt_SHA3_CTX *ctx)
+{
+	gcry_md_open(ctx, GCRY_MD_SHA3_224, 0);
+}
+
+inline void gcrypt_SHA3_256_Init(gcrypt_SHA3_CTX *ctx)
+{
+	gcry_md_open(ctx, GCRY_MD_SHA3_256, 0);
+}
+
+inline void gcrypt_SHA3_384_Init(gcrypt_SHA3_CTX *ctx)
+{
+	gcry_md_open(ctx, GCRY_MD_SHA3_384, 0);
+}
+
+inline void gcrypt_SHA3_512_Init(gcrypt_SHA3_CTX *ctx)
+{
+	gcry_md_open(ctx, GCRY_MD_SHA3_512, 0);
+}
+
+inline void gcrypt_SHA3_Update(gcrypt_SHA3_CTX *ctx, const void *data, size_t len)
+{
+	gcry_md_write(*ctx, data, len);
+}
+
+inline void gcrypt_SHA3_Final(unsigned char *digest, gcrypt_SHA3_CTX *ctx)
+{
+	int algo = gcry_md_get_algo(ctx);
+	unsigned int dlen = gcry_md_get_algo_dlen(algo);
+	memcpy(digest, gcry_md_read(*ctx, algo), dlen);
+}
+
+#define platform_SHA3_CTX gcrypt_SHA3_CTX
+#define platform_SHA3_224_Init gcrypt_SHA3_224_Init
+#define platform_SHA3_256_Init gcrypt_SHA3_256_Init
+#define platform_SHA3_384_Init gcrypt_SHA3_384_Init
+#define platform_SHA3_512_Init gcrypt_SHA3_512_Init
+#define platform_SHA3_Update gcrypt_SHA3_Update
+#define platform_SHA3_Final gcrypt_SHA3_Final
+
+#endif
diff --git a/sha/sha3/sha3.c b/sha/sha3/sha3.c
new file mode 100644
index 000000000000..572cbf88f163
--- /dev/null
+++ b/sha/sha3/sha3.c
@@ -0,0 +1,271 @@
+/*
+ * sha3.c
+ *
+ * an implementation of Secure Hash Algorithm 3 (Keccak) based on:
+ * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
+ * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
+ *
+ * portions derived from RHash/sha3.c
+ *
+ * Copyright (c) 2013, Aleksey Kravchenko <rhash.admin@gmail.com>
+ * Copyright (c) 2019, Michael Clark <michaeljclark@mac.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "git-compat-util.h"
+#include "sha3.h"
+
+/*
+ * macro to expand Keccak 7-term GF(2) round constant:
+ *
+ * (ax^63 + bx^31 + cx^15 + dx^7 + ex^3 + fx + g)
+ *
+ * K(c) -> forall (b in 0...6) |= c[b] << (1 << b) ;
+ */
+#define T(c,b) 0b##c##ull>>b<<63>>(64-(1 << b))
+#define K(c) T(c,0)|T(c,1)|T(c,2)|T(c,3)|T(c,4)|T(c,5)|T(c,6)
+
+/*
+ * expand SHA3 (Keccak) constants for 24 rounds
+ */
+static uint64_t keccak_round_constants[24] = {
+	K(0000001), K(0011010), K(1011110), K(1110000),
+	K(0011111), K(0100001), K(1111001), K(1010101),
+	K(0001110), K(0001100), K(0110101), K(0100110),
+	K(0111111), K(1001111), K(1011101), K(1010011),
+	K(1010010), K(1001000), K(0010110), K(1100110),
+	K(1111001), K(1011000), K(0100001), K(1110100),
+};
+
+static inline uint64_t rol(uint64_t x, int d)
+{
+	return (x << d) | (x >> (64-d));
+}
+
+/* Keccak theta() transformation */
+static void keccak_theta(uint64_t A[25])
+{
+	uint64_t C[5] = {
+		A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20],
+		A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21],
+		A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22],
+		A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23],
+		A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24]
+	};
+
+	uint64_t D[5] = {
+		rol(C[1], 1) ^ C[4],
+		rol(C[2], 1) ^ C[0],
+		rol(C[3], 1) ^ C[1],
+		rol(C[4], 1) ^ C[2],
+		rol(C[0], 1) ^ C[3]
+	};
+
+	for (size_t i = 0; i < 25; i += 5) {
+		A[i + 0] ^= D[0];
+		A[i + 1] ^= D[1];
+		A[i + 2] ^= D[2];
+		A[i + 3] ^= D[3];
+		A[i + 4] ^= D[4];
+	}
+}
+
+/* Keccak pi() transformation */
+static void keccak_pi(uint64_t A[25])
+{
+	uint64_t A1;
+	A1 = A[1];
+	A[ 1] = A[ 6];
+	A[ 6] = A[ 9];
+	A[ 9] = A[22];
+	A[22] = A[14];
+	A[14] = A[20];
+	A[20] = A[ 2];
+	A[ 2] = A[12];
+	A[12] = A[13];
+	A[13] = A[19];
+	A[19] = A[23];
+	A[23] = A[15];
+	A[15] = A[ 4];
+	A[ 4] = A[24];
+	A[24] = A[21];
+	A[21] = A[ 8];
+	A[ 8] = A[16];
+	A[16] = A[ 5];
+	A[ 5] = A[ 3];
+	A[ 3] = A[18];
+	A[18] = A[17];
+	A[17] = A[11];
+	A[11] = A[ 7];
+	A[ 7] = A[10];
+	A[10] = A1;
+	/* note: A[ 0] is left as is */
+}
+
+static inline void ChiStep(uint64_t A[25], size_t i)
+{
+	uint64_t C[5];
+	C[0] = A[0 + i] ^ ~A[1 + i] & A[2 + i];
+	C[1] = A[1 + i] ^ ~A[2 + i] & A[3 + i];
+	C[2] = A[2 + i] ^ ~A[3 + i] & A[4 + i];
+	C[3] = A[3 + i] ^ ~A[4 + i] & A[0 + i];
+	C[4] = A[4 + i] ^ ~A[0 + i] & A[1 + i];
+	A[0 + i] = C[0];
+	A[1 + i] = C[1];
+	A[2 + i] = C[2];
+	A[3 + i] = C[3];
+	A[4 + i] = C[4];
+}
+
+/* Keccak chi() transformation */
+static void keccak_chi(uint64_t A[25])
+{
+	ChiStep(A,0);
+	ChiStep(A,5);
+	ChiStep(A,10);
+	ChiStep(A,15);
+	ChiStep(A,20);
+}
+
+static void keccak_rho(uint64_t A[25])
+{
+	/* apply Keccak rho() transformation */
+	A[ 1] = rol(A[ 1],  1);
+	A[ 2] = rol(A[ 2], 62);
+	A[ 3] = rol(A[ 3], 28);
+	A[ 4] = rol(A[ 4], 27);
+	A[ 5] = rol(A[ 5], 36);
+	A[ 6] = rol(A[ 6], 44);
+	A[ 7] = rol(A[ 7],  6);
+	A[ 8] = rol(A[ 8], 55);
+	A[ 9] = rol(A[ 9], 20);
+	A[10] = rol(A[10],  3);
+	A[11] = rol(A[11], 10);
+	A[12] = rol(A[12], 43);
+	A[13] = rol(A[13], 25);
+	A[14] = rol(A[14], 39);
+	A[15] = rol(A[15], 41);
+	A[16] = rol(A[16], 45);
+	A[17] = rol(A[17], 15);
+	A[18] = rol(A[18], 21);
+	A[19] = rol(A[19],  8);
+	A[20] = rol(A[20], 18);
+	A[21] = rol(A[21],  2);
+	A[22] = rol(A[22], 61);
+	A[23] = rol(A[23], 56);
+	A[24] = rol(A[24], 14);
+}
+
+static void keccak_iota(uint64_t A[25], size_t round)
+{
+	/* apply iota(state, round) */
+	A[0] ^= keccak_round_constants[round];
+}
+
+static void keccak_permutation(uint64_t A[25])
+{
+	for (size_t round = 0; round < 24; round++)
+	{
+		keccak_theta(A);
+		keccak_rho(A);
+		keccak_pi(A);
+		keccak_chi(A);
+		keccak_iota(A, round);
+	}
+}
+
+static void blk_SHA3_Transform(blk_SHA3_CTX* ctx, const unsigned char *buf)
+{
+	size_t block_size = ctx->block_size;
+	for (size_t i = 0; i < block_size/8; i++)
+	{
+		ctx->state[i] ^= le64toh(((uint64_t*)buf)[i]);
+	}
+	keccak_permutation(ctx->state);
+}
+
+static void blk_SHA3_Init(blk_SHA3_CTX* ctx, unsigned bits)
+{
+	/* NB: The Keccak capacity parameter = bits * 2 */
+	unsigned rate = 1600 - bits * 2;
+
+	memset(ctx, 0, sizeof(blk_SHA3_CTX));
+	ctx->block_size = rate / 8;
+	assert(rate <= 1600 && (rate % 64) == 0);
+}
+
+void blk_SHA3_224_Init(blk_SHA3_CTX* ctx) { blk_SHA3_Init(ctx, 224); }
+void blk_SHA3_256_Init(blk_SHA3_CTX* ctx) { blk_SHA3_Init(ctx, 256); }
+void blk_SHA3_384_Init(blk_SHA3_CTX* ctx) { blk_SHA3_Init(ctx, 384); }
+void blk_SHA3_512_Init(blk_SHA3_CTX* ctx) { blk_SHA3_Init(ctx, 512); }
+
+void blk_SHA3_Update(blk_SHA3_CTX* ctx, const void *data, size_t len)
+{
+	unsigned int block_size = ctx->block_size;
+	unsigned int len_buf = ctx->size % block_size;
+
+	ctx->size += len;
+
+	/* Read the data into buf and process blocks as they get full */
+	if (len_buf) {
+		unsigned int left = block_size - len_buf;
+		if (len < left)
+			left = len;
+		memcpy(len_buf + ctx->buf, data, left);
+		len_buf = (len_buf + left) % block_size;
+		len -= left;
+		data = ((const char *)data + left);
+		if (len_buf)
+			return;
+		blk_SHA3_Transform(ctx, ctx->buf);
+	}
+	while (len >= block_size) {
+		blk_SHA3_Transform(ctx, data);
+		data = ((const char *)data + block_size);
+		len -= block_size;
+	}
+	if (len)
+		memcpy(ctx->buf, data, len);
+}
+
+static inline void put_le64(void *ptr, uint64_t value)
+{
+	unsigned char *p = ptr;
+	p[0] = value >>  0;
+	p[1] = value >>  8;
+	p[2] = value >> 16;
+	p[3] = value >> 24;
+	p[4] = value >> 32;
+	p[5] = value >> 40;
+	p[6] = value >> 48;
+	p[7] = value >> 56;
+}
+
+void blk_SHA3_Final(unsigned char* digest, blk_SHA3_CTX* ctx)
+{
+	unsigned int digest_length = 100 - ctx->block_size / 2;
+	unsigned int block_size = ctx->block_size;
+	unsigned int len = ctx->size % block_size, i;
+
+	/* Pad with 0x06, then zeroes, then 0x80 */
+	memset((char*)ctx->buf + len, 0, block_size - len);
+	((char*)ctx->buf)[len] |= 0x06;
+	((char*)ctx->buf)[block_size - 1] |= 0x80;
+
+	/* process final block */
+	blk_SHA3_Transform(ctx, ctx->buf);
+
+	/* copy output */
+	for (i = 0; i < (digest_length+7)/8; i++, digest += sizeof(uint64_t))
+		put_le64(digest, ctx->state[i]);
+}
diff --git a/sha/sha3/sha3.h b/sha/sha3/sha3.h
new file mode 100644
index 000000000000..eb974d69d2b8
--- /dev/null
+++ b/sha/sha3/sha3.h
@@ -0,0 +1,34 @@
+#ifndef SHA3_BLOCK_H
+#define SHA3_BLOCK_H
+
+#define blk_SHA3_224_hash_size 28
+#define blk_SHA3_256_hash_size 32
+#define blk_SHA3_384_hash_size 48
+#define blk_SHA3_512_hash_size 64
+#define blk_SHA3_max_permutation_size 200
+
+typedef struct blk_SHA3_CTX
+{
+	uint64_t state[blk_SHA3_max_permutation_size];
+	uint64_t size;
+	uint64_t block_size;
+	uint8_t buf[blk_SHA3_max_permutation_size];
+} blk_SHA3_CTX;
+
+void blk_SHA3_224_Init(blk_SHA3_CTX* ctx);
+void blk_SHA3_256_Init(blk_SHA3_CTX* ctx);
+void blk_SHA3_384_Init(blk_SHA3_CTX* ctx);
+void blk_SHA3_512_Init(blk_SHA3_CTX* ctx);
+void blk_SHA3_Update(blk_SHA3_CTX* ctx, const void *data, size_t len);
+void blk_SHA3_Final(unsigned char* digest, blk_SHA3_CTX* ctx);
+
+#define platform_SHA3_CTX blk_SHA3_CTX
+#define platform_SHA3_Init blk_SHA3_Init
+#define platform_SHA3_224_Init blk_SHA3_224_Init
+#define platform_SHA3_256_Init blk_SHA3_256_Init
+#define platform_SHA3_384_Init blk_SHA3_384_Init
+#define platform_SHA3_512_Init blk_SHA3_512_Init
+#define platform_SHA3_Update blk_SHA3_Update
+#define platform_SHA3_Final blk_SHA3_Final
+
+#endif
\ No newline at end of file
diff --git a/t/helper/test-sha3.c b/t/helper/test-sha3.c
new file mode 100644
index 000000000000..323936d1bc2e
--- /dev/null
+++ b/t/helper/test-sha3.c
@@ -0,0 +1,22 @@
+#include "test-tool.h"
+#include "cache.h"
+
+int cmd__sha3_224(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA3_224);
+}
+
+int cmd__sha3_256(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA3_256);
+}
+
+int cmd__sha3_384(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA3_384);
+}
+
+int cmd__sha3_512(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA3_512);
+}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 47deff9c6ef4..7acae78e9b87 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -60,6 +60,10 @@ static struct test_cmd cmds[] = {
 	{ "sha512", cmd__sha512 },
 	{ "sha512-224", cmd__sha512_224 },
 	{ "sha512-256", cmd__sha512_256 },
+	{ "sha3-224", cmd__sha3_224 },
+	{ "sha3-256", cmd__sha3_256 },
+	{ "sha3-384", cmd__sha3_384 },
+	{ "sha3-512", cmd__sha3_512 },
 	{ "sigchain", cmd__sigchain },
 	{ "strcmp-offset", cmd__strcmp_offset },
 	{ "string-list", cmd__string_list },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 927540dff7dd..8aa5cee7710b 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -50,6 +50,10 @@ int cmd__sha256(int argc, const char **argv);
 int cmd__sha512(int argc, const char **argv);
 int cmd__sha512_224(int argc, const char **argv);
 int cmd__sha512_256(int argc, const char **argv);
+int cmd__sha3_224(int argc, const char **argv);
+int cmd__sha3_256(int argc, const char **argv);
+int cmd__sha3_384(int argc, const char **argv);
+int cmd__sha3_512(int argc, const char **argv);
 int cmd__sigchain(int argc, const char **argv);
 int cmd__strcmp_offset(int argc, const char **argv);
 int cmd__string_list(int argc, const char **argv);
diff --git a/t/t0015-hash.sh b/t/t0015-hash.sh
index 4735befe1c72..c68a9ef2145c 100755
--- a/t/t0015-hash.sh
+++ b/t/t0015-hash.sh
@@ -132,4 +132,112 @@ test_expect_success 'test basic SHA-512 hash values' '
 
 '
 
+test_expect_success 'test basic SHA3-224 hash values' '
+	test-tool sha3-224 </dev/null >actual &&
+	grep 6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7 actual &&
+	printf "a" | test-tool sha3-224 >actual &&
+	grep 9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b actual &&
+	printf "abc" | test-tool sha3-224 >actual &&
+	grep e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf actual &&
+	printf "message digest" | test-tool sha3-224 >actual &&
+	grep 18768bb4c48eb7fc88e5ddb17efcf2964abd7798a39d86a4b4a1e4c8 actual &&
+	printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha3-224 >actual &&
+	grep 5cdeca81e123f87cad96b9cba999f16f6d41549608d4e0f4681b8239 actual &&
+	# Try to exercise the chunking code by turning autoflush on.
+	perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+		test-tool sha3-224 >actual &&
+	grep d69335b93325192e516a912e6d19a15cb51c6ed5c15243e7a7fd653c actual &&
+	perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+		test-tool sha3-224 >actual &&
+	grep 165efebf793f03c7610d6d5e79462c5f9b7fbcb903f4448038eb35a2 actual &&
+	printf "blob 0\0" | test-tool sha3-224 >actual &&
+	grep f1e72935ac5c52d5c09b408842e207c42e5434424007364fdb468063 actual &&
+	printf "blob 3\0abc" | test-tool sha3-224 >actual &&
+	grep f83c608c9d424b858f66ec80a67ab42409bdc1aae8d7867e6b595e2a actual &&
+	printf "tree 0\0" | test-tool sha3-224 >actual &&
+	grep 1e04f23de0b2b7d1b85e6768fa997a99bd0119dec8158ae0ad07e183 actual
+
+'
+
+test_expect_success 'test basic SHA3-256 hash values' '
+	test-tool sha3-256 </dev/null >actual &&
+	grep a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a actual &&
+	printf "a" | test-tool sha3-256 >actual &&
+	grep 80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b actual &&
+	printf "abc" | test-tool sha3-256 >actual &&
+	grep 3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532 actual &&
+	printf "message digest" | test-tool sha3-256 >actual &&
+	grep edcdb2069366e75243860c18c3a11465eca34bce6143d30c8665cefcfd32bffd actual &&
+	printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha3-256 >actual &&
+	grep 7cab2dc765e21b241dbc1c255ce620b29f527c6d5e7f5f843e56288f0d707521 actual &&
+	# Try to exercise the chunking code by turning autoflush on.
+	perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+		test-tool sha3-256 >actual &&
+	grep 5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1 actual &&
+	perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+		test-tool sha3-256 >actual &&
+	grep 529a361bd6ebbb28deea5a78db2fd714c5b415499d608e37123c4ca130770e6d actual &&
+	printf "blob 0\0" | test-tool sha3-256 >actual &&
+	grep 5aadde7d8ca5b9b352c250ce9b799f5d818893fe89dc52b49f438c8a9ba0a545 actual &&
+	printf "blob 3\0abc" | test-tool sha3-256 >actual &&
+	grep 1a6437dda2a94af5c38246520fd1461886dc46b97ced88b04d43537c603cde6d actual &&
+	printf "tree 0\0" | test-tool sha3-256 >actual &&
+	grep 30211ed485c912e5bc285bd0bd8959ddbfb5875cafb0ae28e0abfa1077b2b214 actual
+
+'
+
+test_expect_success 'test basic SHA3-384 hash values' '
+	test-tool sha3-384 </dev/null >actual &&
+	grep 0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004 actual &&
+	printf "a" | test-tool sha3-384 >actual &&
+	grep 1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9 actual &&
+	printf "abc" | test-tool sha3-384 >actual &&
+	grep ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25 actual &&
+	printf "message digest" | test-tool sha3-384 >actual &&
+	grep d9519709f44af73e2c8e291109a979de3d61dc02bf69def7fbffdfffe662751513f19ad57e17d4b93ba1e484fc1980d5 actual &&
+	printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha3-384 >actual &&
+	grep fed399d2217aaf4c717ad0c5102c15589e1c990cc2b9a5029056a7f7485888d6ab65db2370077a5cadb53fc9280d278f actual &&
+	# Try to exercise the chunking code by turning autoflush on.
+	perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+		test-tool sha3-384 >actual &&
+	grep eee9e24d78c1855337983451df97c8ad9eedf256c6334f8e948d252d5e0e76847aa0774ddb90a842190d2c558b4b8340 actual &&
+	perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+		test-tool sha3-384 >actual &&
+	grep 62c16d1d4366dd40a4c6995168c1e7b35e8e8103403274151a34c5838845a0f3d1a192dadbb0964af7d6941c50f0eb97 actual &&
+	printf "blob 0\0" | test-tool sha3-384 >actual &&
+	grep a53e088abe908d8c9458a8ba955690c417f768031ecf156a1662441faeda502e838f2660164b61a78b15ac75e0f8ded4 actual &&
+	printf "blob 3\0abc" | test-tool sha3-384 >actual &&
+	grep ba0eda34a4b47f9ec8ed996a260efadeb576e4f682b7d0d7d84b4781a210771da519e48f2542431882499fbd21d16935 actual &&
+	printf "tree 0\0" | test-tool sha3-384 >actual &&
+	grep 92e99ae9281a89dc332c9ce8f2831db50ecc54784d51c3ebd5c1151e8fd603fb408abbbb9dcf5713ed21566789ce8059 actual
+
+'
+
+test_expect_success 'test basic SHA3-512 hash values' '
+	test-tool sha3-512 </dev/null >actual &&
+	grep a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26 actual &&
+	printf "a" | test-tool sha3-512 >actual &&
+	grep 697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a actual &&
+	printf "abc" | test-tool sha3-512 >actual &&
+	grep b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0 actual &&
+	printf "message digest" | test-tool sha3-512 >actual &&
+	grep 3444e155881fa15511f57726c7d7cfe80302a7433067b29d59a71415ca9dd141ac892d310bc4d78128c98fda839d18d7f0556f2fe7acb3c0cda4bff3a25f5f59 actual &&
+	printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha3-512 >actual &&
+	grep af328d17fa28753a3c9f5cb72e376b90440b96f0289e5703b729324a975ab384eda565fc92aaded143669900d761861687acdc0a5ffa358bd0571aaad80aca68 actual &&
+	# Try to exercise the chunking code by turning autoflush on.
+	perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+		test-tool sha3-512 >actual &&
+	grep 3c3a876da14034ab60627c077bb98f7e120a2a5370212dffb3385a18d4f38859ed311d0a9d5141ce9cc5c66ee689b266a8aa18ace8282a0e0db596c90b0a7b87 actual &&
+	perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+		test-tool sha3-512 >actual &&
+	grep 06b2e52cc7595712651351cdc6726acdebba682844c7983f66089158433975e4d2caf6c0efc4c7018cd2da73df53047f19a79935941025db4aaf1bd876c49ad6 actual &&
+	printf "blob 0\0" | test-tool sha3-512 >actual &&
+	grep 4353a50d0d3d8edd231763fb0102116286aa6d760a772133e32c124a998a19467d789064dd763e57b547ff3a31882da3d2031378cfe0fa5774c12eea51055a51 actual &&
+	printf "blob 3\0abc" | test-tool sha3-512 >actual &&
+	grep 89de02c66a3beca3411b5a72699fe8389d574b7d59ca17d42cba7a83cd03423388b1c4248cd8a3cce73a0768948fe1a800c155c24378334f6ae2bb8c5bf48284 actual &&
+	printf "tree 0\0" | test-tool sha3-512 >actual &&
+	grep 8f86cb67ce0a8bc865b300733c27dade0ea8fe66299b4bc6368ec84f53134c367c66f0e3376261ab5a86d722ad0d98391a3c1c472d6791da464a7836006de12c actual
+
+'
+
 test_done
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/6] Add an implementation of the SHA224 truncated hash algorithm
  2019-12-22  6:48 [PATCH 0/6] Additional SHA implementations Michael Clark
                   ` (2 preceding siblings ...)
  2019-12-22  6:48 ` [PATCH 3/6] Add an implementation of the SHA-3 " Michael Clark
@ 2019-12-22  6:48 ` Michael Clark
  2019-12-22  6:48 ` [PATCH 5/6] Add OpenSSL EVP interface for SHA-3 and SHA-512 algorithms Michael Clark
  2019-12-22  6:48 ` [PATCH 6/6] Add sha/README.md with table of SHA algorithm details Michael Clark
  5 siblings, 0 replies; 7+ messages in thread
From: Michael Clark @ 2019-12-22  6:48 UTC (permalink / raw)
  To: git; +Cc: Michael Clark

- Update existing SHA256 implementation adding initialization
  vector for SHA224 and add algorithm to list of hash algos.
- Add sha224 commands to test-tool.
- Add sha224 hash tests to t/t0015-hash.sh
---
 hash.h                 | 34 +++++++++++++++++++++++++++-------
 sha/sha256/gcrypt.h    | 15 ++++++++++++++-
 sha/sha256/sha256.c    | 18 +++++++++++++++++-
 sha/sha256/sha256.h    |  9 +++++++++
 sha1-file.c            | 41 +++++++++++++++++++++++++++++++++++++++++
 t/helper/test-sha256.c |  5 +++++
 t/helper/test-tool.c   |  1 +
 t/helper/test-tool.h   |  1 +
 t/t0015-hash.sh        | 26 ++++++++++++++++++++++++++
 9 files changed, 141 insertions(+), 9 deletions(-)

diff --git a/hash.h b/hash.h
index 4826de3c80d4..16924203d035 100644
--- a/hash.h
+++ b/hash.h
@@ -54,6 +54,18 @@
 #define git_SHA1_Update		platform_SHA1_Update
 #define git_SHA1_Final		platform_SHA1_Final
 
+#ifndef platform_SHA224_CTX
+#define platform_SHA224_CTX	SHA224_CTX
+#define platform_SHA224_Init	SHA224_Init
+#define platform_SHA224_Update	SHA224_Update
+#define platform_SHA224_Final	SHA224_Final
+#endif
+
+#define git_SHA224_CTX		platform_SHA224_CTX
+#define git_SHA224_Init		platform_SHA224_Init
+#define git_SHA224_Update	platform_SHA224_Update
+#define git_SHA224_Final	platform_SHA224_Final
+
 #ifndef platform_SHA256_CTX
 #define platform_SHA256_CTX	SHA256_CTX
 #define platform_SHA256_Init	SHA256_Init
@@ -101,20 +113,22 @@
 #define GIT_HASH_SHA1 1
 /* SHA-256  */
 #define GIT_HASH_SHA256 2
+/* SHA-224  */
+#define GIT_HASH_SHA224 3
 /* SHA-512  */
-#define GIT_HASH_SHA512 3
+#define GIT_HASH_SHA512 4
 /* SHA-512-224  */
-#define GIT_HASH_SHA512_224 4
+#define GIT_HASH_SHA512_224 5
 /* SHA-512-256  */
-#define GIT_HASH_SHA512_256 5
+#define GIT_HASH_SHA512_256 6
 /* SHA-3-224 */
-#define GIT_HASH_SHA3_224 6
+#define GIT_HASH_SHA3_224 7
 /* SHA-3-256 */
-#define GIT_HASH_SHA3_256 7
+#define GIT_HASH_SHA3_256 8
 /* SHA-3-384 */
-#define GIT_HASH_SHA3_384 8
+#define GIT_HASH_SHA3_384 9
 /* SHA-3-512 */
-#define GIT_HASH_SHA3_512 9
+#define GIT_HASH_SHA3_512 10
 /* Number of algorithms supported (including unknown). */
 #define GIT_HASH_NALGOS (GIT_HASH_SHA3_512 + 1)
 
@@ -188,6 +202,12 @@ static inline int hash_algo_by_ptr(const struct git_hash_algo *p)
 /* The block size of SHA-1. */
 #define GIT_SHA1_BLKSZ 64
 
+/* The length in bytes and in hex digits of an object name (SHA-224 value). */
+#define GIT_SHA224_RAWSZ 28
+#define GIT_SHA224_HEXSZ (2 * GIT_SHA224_RAWSZ)
+/* The block size of SHA-224. */
+#define GIT_SHA224_BLKSZ 64
+
 /* The length in bytes and in hex digits of an object name (SHA-256 value). */
 #define GIT_SHA256_RAWSZ 32
 #define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
diff --git a/sha/sha256/gcrypt.h b/sha/sha256/gcrypt.h
index 09bd8bb20062..3de8614eb1d8 100644
--- a/sha/sha256/gcrypt.h
+++ b/sha/sha256/gcrypt.h
@@ -3,10 +3,16 @@
 
 #include <gcrypt.h>
 
+#define SHA224_DIGEST_SIZE 28
 #define SHA256_DIGEST_SIZE 32
 
 typedef gcry_md_hd_t gcrypt_SHA256_CTX;
 
+inline void gcrypt_SHA224_Init(gcrypt_SHA256_CTX *ctx)
+{
+	gcry_md_open(ctx, GCRY_MD_SHA224, 0);
+}
+
 inline void gcrypt_SHA256_Init(gcrypt_SHA256_CTX *ctx)
 {
 	gcry_md_open(ctx, GCRY_MD_SHA256, 0);
@@ -19,7 +25,9 @@ inline void gcrypt_SHA256_Update(gcrypt_SHA256_CTX *ctx, const void *data, size_
 
 inline void gcrypt_SHA256_Final(unsigned char *digest, gcrypt_SHA256_CTX *ctx)
 {
-	memcpy(digest, gcry_md_read(*ctx, GCRY_MD_SHA256), SHA256_DIGEST_SIZE);
+	int algo = gcry_md_get_algo(ctx);
+	unsigned int dlen = gcry_md_get_algo_dlen(algo);
+	memcpy(digest, gcry_md_read(*ctx, algo), dlen);
 }
 
 #define platform_SHA256_CTX gcrypt_SHA256_CTX
@@ -27,4 +35,9 @@ inline void gcrypt_SHA256_Final(unsigned char *digest, gcrypt_SHA256_CTX *ctx)
 #define platform_SHA256_Update gcrypt_SHA256_Update
 #define platform_SHA256_Final gcrypt_SHA256_Final
 
+#define platform_SHA224_CTX gcrypt_SHA256_CTX
+#define platform_SHA224_Init gcrypt_SHA224_Init
+#define platform_SHA224_Update gcrypt_SHA256_Update
+#define platform_SHA224_Final gcrypt_SHA256_Final
+
 #endif
diff --git a/sha/sha256/sha256.c b/sha/sha256/sha256.c
index 37850b4e52e0..a774d7562d6e 100644
--- a/sha/sha256/sha256.c
+++ b/sha/sha256/sha256.c
@@ -6,8 +6,24 @@
 
 #define BLKSIZE blk_SHA256_BLKSIZE
 
+void blk_SHA224_Init(blk_SHA256_CTX *ctx)
+{
+	ctx->digestlen = blk_SHA224_HASHSIZE;
+	ctx->offset = 0;
+	ctx->size = 0;
+	ctx->state[0] = 0xc1059ed8ul;
+	ctx->state[1] = 0x367cd507ul;
+	ctx->state[2] = 0x3070dd17ul;
+	ctx->state[3] = 0xf70e5939ul;
+	ctx->state[4] = 0xffc00b31ul;
+	ctx->state[5] = 0x68581511ul;
+	ctx->state[6] = 0x64f98fa7ul;
+	ctx->state[7] = 0xbefa4fa4ul;
+}
+
 void blk_SHA256_Init(blk_SHA256_CTX *ctx)
 {
+	ctx->digestlen = blk_SHA256_HASHSIZE;
 	ctx->offset = 0;
 	ctx->size = 0;
 	ctx->state[0] = 0x6a09e667ul;
@@ -191,6 +207,6 @@ void blk_SHA256_Final(unsigned char *digest, blk_SHA256_CTX *ctx)
 	blk_SHA256_Update(ctx, padlen, 8);
 
 	/* copy output */
-	for (i = 0; i < 8; i++, digest += sizeof(uint32_t))
+	for (i = 0; i < (ctx->digestlen >> 2); i++, digest += sizeof(uint32_t))
 		put_be32(digest, ctx->state[i]);
 }
diff --git a/sha/sha256/sha256.h b/sha/sha256/sha256.h
index 5099d6421d37..e513eafa8199 100644
--- a/sha/sha256/sha256.h
+++ b/sha/sha256/sha256.h
@@ -2,16 +2,20 @@
 #define SHA256_BLOCK_SHA256_H
 
 #define blk_SHA256_BLKSIZE 64
+#define blk_SHA224_HASHSIZE 28
+#define blk_SHA256_HASHSIZE 32
 
 struct blk_SHA256_CTX {
 	uint32_t state[8];
 	uint64_t size;
 	uint32_t offset;
+	uint32_t digestlen;
 	uint8_t buf[blk_SHA256_BLKSIZE];
 };
 
 typedef struct blk_SHA256_CTX blk_SHA256_CTX;
 
+void blk_SHA224_Init(blk_SHA256_CTX *ctx);
 void blk_SHA256_Init(blk_SHA256_CTX *ctx);
 void blk_SHA256_Update(blk_SHA256_CTX *ctx, const void *data, size_t len);
 void blk_SHA256_Final(unsigned char *digest, blk_SHA256_CTX *ctx);
@@ -21,4 +25,9 @@ void blk_SHA256_Final(unsigned char *digest, blk_SHA256_CTX *ctx);
 #define platform_SHA256_Update blk_SHA256_Update
 #define platform_SHA256_Final blk_SHA256_Final
 
+#define platform_SHA224_CTX blk_SHA256_CTX
+#define platform_SHA224_Init blk_SHA224_Init
+#define platform_SHA224_Update blk_SHA256_Update
+#define platform_SHA224_Final blk_SHA256_Final
+
 #endif
diff --git a/sha1-file.c b/sha1-file.c
index 1f5b835a9f24..b73847bea5d2 100644
--- a/sha1-file.c
+++ b/sha1-file.c
@@ -40,6 +40,10 @@
 #define EMPTY_TREE_SHA1_BIN_LITERAL \
 	 "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
 	 "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
+#define EMPTY_TREE_SHA224_BIN_LITERAL \
+	"\xc8\x24\x29\x25\x0d\x41\x1b\x49\x91\xa3" \
+	"\xde\x9b\x42\xf5\x00\x90\x8a\x4a\x24\x2a" \
+	"\x8d\x3b\x34\x85\xe5\xe3\xbf\x71"
 #define EMPTY_TREE_SHA256_BIN_LITERAL \
 	"\x6e\xf1\x9b\x41\x22\x5c\x53\x69\xf1\xc1" \
 	"\x04\xd4\x5d\x8d\x85\xef\xa9\xb0\x57\xb5" \
@@ -89,6 +93,10 @@
 #define EMPTY_BLOB_SHA1_BIN_LITERAL \
 	"\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
 	"\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
+#define EMPTY_BLOB_SHA224_BIN_LITERAL \
+	"\xfc\xdd\x1b\x16\x6d\xde\x80\x33\x06\xa4" \
+	"\x48\x52\xe0\xb7\xdc\xdf\x73\xba\xd0\xde" \
+	"\xc5\x6f\x00\x1f\xeb\x39\xea\x89"
 #define EMPTY_BLOB_SHA256_BIN_LITERAL \
 	"\x47\x3a\x0f\x4c\x3b\xe8\xa9\x36\x81\xa2" \
 	"\x67\xe3\xb1\xe9\xa7\xdc\xda\x11\x85\x43" \
@@ -142,6 +150,12 @@ static const struct object_id empty_tree_oid = {
 static const struct object_id empty_blob_oid = {
 	EMPTY_BLOB_SHA1_BIN_LITERAL
 };
+static const struct object_id empty_tree_oid_sha224 = {
+	EMPTY_TREE_SHA224_BIN_LITERAL
+};
+static const struct object_id empty_blob_oid_sha224 = {
+	EMPTY_BLOB_SHA224_BIN_LITERAL
+};
 static const struct object_id empty_tree_oid_sha256 = {
 	EMPTY_TREE_SHA256_BIN_LITERAL
 };
@@ -206,6 +220,20 @@ static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
 	git_SHA1_Final(hash, &ctx->sha1);
 }
 
+static void git_hash_sha224_init(git_hash_ctx *ctx)
+{
+	git_SHA224_Init(&ctx->sha256);
+}
+
+static void git_hash_sha224_update(git_hash_ctx *ctx, const void *data, size_t len)
+{
+	git_SHA224_Update(&ctx->sha256, data, len);
+}
+
+static void git_hash_sha224_final(unsigned char *hash, git_hash_ctx *ctx)
+{
+	git_SHA224_Final(hash, &ctx->sha256);
+}
 
 static void git_hash_sha256_init(git_hash_ctx *ctx)
 {
@@ -331,6 +359,19 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
 		&empty_tree_oid_sha256,
 		&empty_blob_oid_sha256,
 	},
+	{
+		"sha224",
+		/* "s224", big-endian */
+		0x73323234,
+		GIT_SHA224_RAWSZ,
+		GIT_SHA224_HEXSZ,
+		GIT_SHA224_BLKSZ,
+		git_hash_sha224_init,
+		git_hash_sha224_update,
+		git_hash_sha224_final,
+		&empty_tree_oid_sha224,
+		&empty_blob_oid_sha224,
+	},
 	{
 		"sha512",
 		/* "s512", big-endian */
diff --git a/t/helper/test-sha256.c b/t/helper/test-sha256.c
index 0ac6a99d5f2a..f79aca916128 100644
--- a/t/helper/test-sha256.c
+++ b/t/helper/test-sha256.c
@@ -1,6 +1,11 @@
 #include "test-tool.h"
 #include "cache.h"
 
+int cmd__sha224(int ac, const char **av)
+{
+	return cmd_hash_impl(ac, av, GIT_HASH_SHA224);
+}
+
 int cmd__sha256(int ac, const char **av)
 {
 	return cmd_hash_impl(ac, av, GIT_HASH_SHA256);
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 7acae78e9b87..762c4cb01d19 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -56,6 +56,7 @@ static struct test_cmd cmds[] = {
 	{ "serve-v2", cmd__serve_v2 },
 	{ "sha1", cmd__sha1 },
 	{ "sha1-array", cmd__sha1_array },
+	{ "sha224", cmd__sha224 },
 	{ "sha256", cmd__sha256 },
 	{ "sha512", cmd__sha512 },
 	{ "sha512-224", cmd__sha512_224 },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 8aa5cee7710b..e4f63baef948 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -46,6 +46,7 @@ int cmd__scrap_cache_tree(int argc, const char **argv);
 int cmd__serve_v2(int argc, const char **argv);
 int cmd__sha1(int argc, const char **argv);
 int cmd__sha1_array(int argc, const char **argv);
+int cmd__sha224(int argc, const char **argv);
 int cmd__sha256(int argc, const char **argv);
 int cmd__sha512(int argc, const char **argv);
 int cmd__sha512_224(int argc, const char **argv);
diff --git a/t/t0015-hash.sh b/t/t0015-hash.sh
index c68a9ef2145c..225145d52653 100755
--- a/t/t0015-hash.sh
+++ b/t/t0015-hash.sh
@@ -52,6 +52,32 @@ test_expect_success 'test basic SHA-256 hash values' '
 	grep 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321 actual
 '
 
+test_expect_success 'test basic SHA-224 hash values' '
+	test-tool sha224 </dev/null >actual &&
+	grep d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f actual &&
+	printf "a" | test-tool sha224 >actual &&
+	grep abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5 actual &&
+	printf "abc" | test-tool sha224 >actual &&
+	grep 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7 actual &&
+	printf "message digest" | test-tool sha224 >actual &&
+	grep 2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb actual &&
+	printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha224 >actual &&
+	grep 45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2 actual &&
+	# Try to exercise the chunking code by turning autoflush on.
+	perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | \
+		test-tool sha224 >actual &&
+	grep 20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67 actual &&
+	perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | \
+		test-tool sha224 >actual &&
+	grep 22c732697633e465ba836e11c7829ee185a72b53fbf35fde511bfbcd actual &&
+	printf "blob 0\0" | test-tool sha224 >actual &&
+	grep fcdd1b166dde803306a44852e0b7dcdf73bad0dec56f001feb39ea89 actual &&
+	printf "blob 3\0abc" | test-tool sha224 >actual &&
+	grep 22d78642a42d232e5b21911de160bed5b033badbecb8fc8b693e6ffe actual &&
+	printf "tree 0\0" | test-tool sha224 >actual &&
+	grep c82429250d411b4991a3de9b42f500908a4a242a8d3b3485e5e3bf71 actual
+'
+
 test_expect_success 'test basic SHA-512/224 hash values' '
 	test-tool sha512-224 </dev/null >actual &&
 	grep 6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4 actual &&
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/6] Add OpenSSL EVP interface for SHA-3 and SHA-512 algorithms
  2019-12-22  6:48 [PATCH 0/6] Additional SHA implementations Michael Clark
                   ` (3 preceding siblings ...)
  2019-12-22  6:48 ` [PATCH 4/6] Add an implementation of the SHA224 truncated " Michael Clark
@ 2019-12-22  6:48 ` Michael Clark
  2019-12-22  6:48 ` [PATCH 6/6] Add sha/README.md with table of SHA algorithm details Michael Clark
  5 siblings, 0 replies; 7+ messages in thread
From: Michael Clark @ 2019-12-22  6:48 UTC (permalink / raw)
  To: git; +Cc: Michael Clark

- Add OpenSSL EVP context wrapper and interface.
- Add configuration machinery to select SHA-3 and SHA-512 impls
  from OpenSSL using the EVP interface.
- Use `make OPENSSL_EVP=1` to build using the OpenSSL EVP impls
  for all SHA-3 and SHA-512 algos.
---
 Makefile              |  9 +++-
 hash.h                |  6 +++
 sha/sha_evp/sha_evp.c | 99 +++++++++++++++++++++++++++++++++++++++++++
 sha/sha_evp/sha_evp.h | 51 ++++++++++++++++++++++
 4 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 sha/sha_evp/sha_evp.c
 create mode 100644 sha/sha_evp/sha_evp.h

diff --git a/Makefile b/Makefile
index 6bf9900291cb..e065630e24fa 100644
--- a/Makefile
+++ b/Makefile
@@ -189,6 +189,8 @@ all::
 #
 # Define OPENSSL_SHA256 to use the SHA-256 routines in OpenSSL.
 #
+# Define OPENSSL_EVP to use the SHA-3 and SHA-512 routines in OpenSSL.
+#
 # Define NEEDS_CRYPTO_WITH_SSL if you need -lcrypto when using -lssl (Darwin).
 #
 # Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin).
@@ -1716,6 +1718,11 @@ else
 endif
 endif
 
+ifdef OPENSSL_EVP
+	EXTLIBS += $(LIB_4_CRYPTO)
+	BASIC_CFLAGS += -DSHA_EVP_OPENSSL
+	LIB_OBJS += sha/sha_evp/sha_evp.o
+else
 ifdef GCRYPT_SHA512
 	BASIC_CFLAGS += -DSHA512_GCRYPT
 	EXTLIBS += -lgcrypt
@@ -1723,7 +1730,6 @@ else
 	LIB_OBJS += sha/sha512/sha512.o
 	BASIC_CFLAGS += -DSHA512_BLK
 endif
-
 ifdef GCRYPT_SHA3
 	BASIC_CFLAGS += -DSHA3_GCRYPT
 	EXTLIBS += -lgcrypt
@@ -1731,6 +1737,7 @@ else
 	LIB_OBJS += sha/sha3/sha3.o
 	BASIC_CFLAGS += -DSHA3_BLK
 endif
+endif
 
 ifdef SHA1_MAX_BLOCK_SIZE
 	LIB_OBJS += compat/sha1-chunked.o
diff --git a/hash.h b/hash.h
index 16924203d035..38e691fe8961 100644
--- a/hash.h
+++ b/hash.h
@@ -25,12 +25,18 @@
 
 #if defined(SHA512_GCRYPT)
 #include "sha/sha512/gcrypt.h"
+#elif defined(SHA_EVP_OPENSSL)
+#include <openssl/evp.h>
+#include "sha/sha_evp/sha_evp.h"
 #else
 #include "sha/sha512/sha512.h"
 #endif
 
 #if defined(SHA3_GCRYPT)
 #include "sha/sha3/gcrypt.h"
+#elif defined(SHA_EVP_OPENSSL)
+#include <openssl/evp.h>
+#include "sha/sha_evp/sha_evp.h"
 #else
 #include "sha/sha3/sha3.h"
 #endif
diff --git a/sha/sha_evp/sha_evp.c b/sha/sha_evp/sha_evp.c
new file mode 100644
index 000000000000..6871f9744a71
--- /dev/null
+++ b/sha/sha_evp/sha_evp.c
@@ -0,0 +1,99 @@
+#include "git-compat-util.h"
+#include "sha_evp.h"
+
+void evp_SHA2_224_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha224();
+}
+
+void evp_SHA2_256_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha256();
+}
+
+void evp_SHA2_512_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha512();
+}
+
+void evp_SHA2_512_224_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha512_224();
+}
+
+void evp_SHA2_512_256_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha512_256();
+}
+
+void evp_SHA3_224_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha3_224();
+}
+
+void evp_SHA3_256_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha3_256();
+}
+
+void evp_SHA3_384_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha3_384();
+}
+
+void evp_SHA3_512_Init(SHA_EVP_CTX *ctx)
+{
+	ctx->digest_ctx = NULL;
+	ctx->digest_md = EVP_sha3_512();
+}
+
+static void evp_SHA_Lazy_Init(SHA_EVP_CTX *ctx)
+{
+	/*
+	 * The OpenSSL EVP digest API requires a dynamically sized context to be
+	 * allocated and destroyed, however, the digest API we are emulating uses
+	 * static structures and thus has no allocation or deallocation API.
+	 *
+	 * Due to this, we must call EVP_MD_CTX_destroy in Final to free up
+	 * dynamically allocated memory. Context creation is thus done lazily in
+	 * either Update or Final to handle cases where the context is reused
+	 * after Final has been called.
+ 	 */
+	if (ctx->digest_ctx) return;
+	if ((ctx->digest_ctx = EVP_MD_CTX_create()) == NULL)
+		abort();
+	if (EVP_DigestInit_ex(ctx->digest_ctx, ctx->digest_md, NULL) != 1)
+		abort();
+}
+
+void evp_SHA_Update(SHA_EVP_CTX *ctx, const void *data, size_t len)
+{
+	/* handle late Init as well as being called again after Final */
+	evp_SHA_Lazy_Init(ctx);
+
+	if (EVP_DigestUpdate(ctx->digest_ctx, data, len) != 1)
+		abort();
+}
+
+void evp_SHA_Final(unsigned char *result, SHA_EVP_CTX *ctx)
+{
+	unsigned int len;
+
+	/* handle case where Final is called without Update (empty hash) */
+	evp_SHA_Lazy_Init(ctx);
+
+	if (EVP_DigestFinal_ex(ctx->digest_ctx, result, &len) != 1)
+		abort();
+	assert(EVP_MD_size(ctx->digest_md) == len);
+
+	EVP_MD_CTX_destroy(ctx->digest_ctx);
+	ctx->digest_ctx = NULL;
+}
diff --git a/sha/sha_evp/sha_evp.h b/sha/sha_evp/sha_evp.h
new file mode 100644
index 000000000000..8757f77f4c13
--- /dev/null
+++ b/sha/sha_evp/sha_evp.h
@@ -0,0 +1,51 @@
+#ifndef SHAEVP_BLOCK_H
+#define SHAEVP_BLOCK_H
+
+#include <openssl/evp.h>
+
+#define evp_SHA2_256_hash_size      32
+#define evp_SHA2_512_224_hash_size  28
+#define evp_SHA2_512_256_hash_size  32
+#define evp_SHA2_512_hash_size      64
+#define evp_SHA3_224_hash_size      28
+#define evp_SHA3_256_hash_size      32
+#define evp_SHA3_384_hash_size      48
+#define evp_SHA3_512_hash_size      64
+
+struct SHA_EVP_CTX {
+	EVP_MD_CTX *digest_ctx;
+	const EVP_MD* digest_md;
+};
+
+typedef struct SHA_EVP_CTX SHA_EVP_CTX;
+
+void evp_SHA2_224_Init(SHA_EVP_CTX *ctx);
+void evp_SHA2_256_Init(SHA_EVP_CTX *ctx);
+void evp_SHA2_512_Init(SHA_EVP_CTX *ctx);
+void evp_SHA2_512_224_Init(SHA_EVP_CTX *ctx);
+void evp_SHA2_512_256_Init(SHA_EVP_CTX *ctx);
+void evp_SHA3_224_Init(SHA_EVP_CTX *ctx);
+void evp_SHA3_256_Init(SHA_EVP_CTX *ctx);
+void evp_SHA3_384_Init(SHA_EVP_CTX *ctx);
+void evp_SHA3_512_Init(SHA_EVP_CTX *ctx);
+
+void evp_SHA_Update(SHA_EVP_CTX *ctx, const void *data, size_t len);
+void evp_SHA_Final(unsigned char *result, SHA_EVP_CTX *ctx);
+
+#define platform_SHA512_CTX SHA_EVP_CTX
+#define platform_SHA512_Init evp_SHA2_512_Init
+#define platform_SHA512_224_Init evp_SHA2_512_224_Init
+#define platform_SHA512_256_Init evp_SHA2_512_256_Init
+#define platform_SHA512_Update evp_SHA_Update
+#define platform_SHA512_Final evp_SHA_Final
+
+#define platform_SHA3_CTX SHA_EVP_CTX
+#define platform_SHA3_Init evp_SHA3_256_Init
+#define platform_SHA3_224_Init evp_SHA3_224_Init
+#define platform_SHA3_256_Init evp_SHA3_256_Init
+#define platform_SHA3_384_Init evp_SHA3_384_Init
+#define platform_SHA3_512_Init evp_SHA3_512_Init
+#define platform_SHA3_Update evp_SHA_Update
+#define platform_SHA3_Final evp_SHA_Final
+
+#endif
\ No newline at end of file
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 6/6] Add sha/README.md with table of SHA algorithm details
  2019-12-22  6:48 [PATCH 0/6] Additional SHA implementations Michael Clark
                   ` (4 preceding siblings ...)
  2019-12-22  6:48 ` [PATCH 5/6] Add OpenSSL EVP interface for SHA-3 and SHA-512 algorithms Michael Clark
@ 2019-12-22  6:48 ` Michael Clark
  5 siblings, 0 replies; 7+ messages in thread
From: Michael Clark @ 2019-12-22  6:48 UTC (permalink / raw)
  To: git; +Cc: Michael Clark

- Add table showing algorith name, mnemonic, type-code, wdith,
  and library implementation (builtin, gcrypt, OpenSSL, EVP).
---
 sha/README.md | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 sha/README.md

diff --git a/sha/README.md b/sha/README.md
new file mode 100644
index 000000000000..0e24049e4cc7
--- /dev/null
+++ b/sha/README.md
@@ -0,0 +1,23 @@
+# SHA algorithms
+
+### Algorithms
+
+Table showing details of the SHA algorithms:
+
+| algorithm      | mnemonic | type-code    | width | extension | builtin      | gcrypt | OpenSSL| EVP    |
+|:---------------|:---------|:-------------|------:|----------:|:-------------|:-------|:-------|:-------|
+| `sha1`         | `sha1`   | `0x73686131` | 160   | yes       | `sha/sha1`   | yes    | yes    | -      |
+| `sha256`       | `s256`   | `0x73323536` | 256   | yes       | `sha/sha256` | yes    | yes    | -      |
+| `sha224`       | `s224`   | `0x73323234` | 224   | no        | `sha/sha256` | yes    | yes    | -      |
+| `sha512`       | `s512`   | `0x73353132` | 512   | yes       | `sha/sha512` | yes    | yes    | yes    |
+| `sha512/224`   | `s226`   | `0x73323236` | 224   | no        | `sha/sha512` | yes    | yes    | yes    |
+| `sha512/256`   | `s228`   | `0x73323238` | 256   | no        | `sha/sha512` | yes    | yes    | yes    |
+| `sha3-224`     | `s388`   | `0x73333838` | 224   | no        | `sha/sha3`   | yes    | -      | yes    |
+| `sha3-256`     | `s398`   | `0x73333938` | 256   | no        | `sha/sha3`   | yes    | -      | yes    |
+| `sha3-384`     | `s3a8`   | `0x73336138` | 384   | no        | `sha/sha3`   | yes    | -      | yes    |
+| `sha3-512`     | `s3b8`   | `0x73336238` | 512   | no        | `sha/sha3`   | yes    | -      | yes    |
+
+#### Notes
+
+- The _'extension'_ column refers to whether the algorithm is vulnerable to the
+ [length extension attack](https://en.wikipedia.org/wiki/Length_extension_attack).
\ No newline at end of file
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-12-22  6:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-22  6:48 [PATCH 0/6] Additional SHA implementations Michael Clark
2019-12-22  6:48 ` [PATCH 1/6] Move all SHA algorithm variants into sha/ directory Michael Clark
2019-12-22  6:48 ` [PATCH 2/6] Add an implementation of the SHA-512 hash algorithm Michael Clark
2019-12-22  6:48 ` [PATCH 3/6] Add an implementation of the SHA-3 " Michael Clark
2019-12-22  6:48 ` [PATCH 4/6] Add an implementation of the SHA224 truncated " Michael Clark
2019-12-22  6:48 ` [PATCH 5/6] Add OpenSSL EVP interface for SHA-3 and SHA-512 algorithms Michael Clark
2019-12-22  6:48 ` [PATCH 6/6] Add sha/README.md with table of SHA algorithm details Michael Clark

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).