diff mbox series

[5/6] Add OpenSSL EVP interface for SHA-3 and SHA-512 algorithms

Message ID 20191222064809.35667-6-michaeljclark@mac.com (mailing list archive)
State New, archived
Headers show
Series Additional SHA implementations | expand

Commit Message

Michael Clark Dec. 22, 2019, 6:48 a.m. UTC
- 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 mbox series

Patch

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