diff --git a/contrib/vstudio/vc17/zlibstat.vcxproj b/contrib/vstudio/vc17/zlibstat.vcxproj
index b946ac2a90..4cb5944b80 100644
--- a/contrib/vstudio/vc17/zlibstat.vcxproj
+++ b/contrib/vstudio/vc17/zlibstat.vcxproj
@@ -58,7 +58,7 @@
StaticLibrary
false
- v143
+ v142
StaticLibrary
@@ -288,7 +288,7 @@
OnlyExplicitInline
- ..\..\..;%(AdditionalIncludeDirectories)
+ ..\..\..;C:\Basis\Projects\CyberTriage\CyberTriageTool\mbedTLS_3.6.2\include;%(AdditionalIncludeDirectories)
WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)
true
@@ -310,6 +310,8 @@
/MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions)
$(OutDir)zlibstat.lib
true
+ mbedtls.lib
+ C:\Basis\Projects\CyberTriage\CyberTriageTool\mbedTLS_3.6.2\Release_XPNoLibs;%(AdditionalLibraryDirectories)
diff --git a/gzclose.c b/gzclose.c
index 48d6a86f04..eb3795f4b5 100644
--- a/gzclose.c
+++ b/gzclose.c
@@ -21,3 +21,35 @@ int ZEXPORT gzclose(gzFile file) {
return gzclose_r(file);
#endif
}
+
+void ZEXPORT gz_hash_init(gzFile file) {
+ gz_statep state;
+
+ if (file == NULL)
+ return;
+ state = (gz_statep)file;
+
+ mbedtls_sha256_init(&(state->strm.sha256_context));
+ int ret = mbedtls_sha256_starts(&(state->strm.sha256_context), 0);
+ if (ret != 0) {
+ // Stream state should still be set to Z_SHA256_STATE_UNINITIALIZED
+ mbedtls_sha256_free(&(state->strm.sha256_context));
+ }
+ else {
+ state->strm.sha256_ret = Z_SHA256_STATE_ACTIVE;
+ }
+}
+
+int ZEXPORT gzclose_hash(gzFile file, unsigned char hashBuf[32], z_off64_t* compressedSize) {
+#ifndef NO_GZCOMPRESS
+ gz_statep state;
+
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ return state->mode == GZ_READ ? gzclose_r(file) : gzclose_hash_w(file, hashBuf, compressedSize);
+#else
+ return gzclose_r(file);
+#endif
+}
diff --git a/gzlib.c b/gzlib.c
index 983153cc8e..e0a54a76da 100644
--- a/gzlib.c
+++ b/gzlib.c
@@ -105,6 +105,8 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
state->want = GZBUFSIZE; /* requested buffer size */
state->msg = NULL; /* no error message yet */
+ state->strm.sha256_ret = Z_SHA256_STATE_UNINITIALIZED;
+
/* interpret mode */
state->mode = GZ_NONE;
state->level = Z_DEFAULT_COMPRESSION;
diff --git a/gzwrite.c b/gzwrite.c
index 435b4621b5..f1b1d915c7 100644
--- a/gzwrite.c
+++ b/gzwrite.c
@@ -75,6 +75,11 @@ local int gz_comp(gz_statep state, int flush) {
if (state->direct) {
while (strm->avail_in) {
put = strm->avail_in > max ? max : strm->avail_in;
+ if (strm->sha256_ret == Z_SHA256_STATE_ACTIVE) {
+ if (0 != mbedtls_sha256_update(&(strm->sha256_context), strm->next_in, put)) {
+ strm->sha256_ret = Z_SHA256_STATE_ERROR;
+ }
+ }
writ = write(state->fd, strm->next_in, put);
if (writ < 0) {
gz_error(state, Z_ERRNO, zstrerror());
@@ -105,6 +110,11 @@ local int gz_comp(gz_statep state, int flush) {
while (strm->next_out > state->x.next) {
put = strm->next_out - state->x.next > (int)max ? max :
(unsigned)(strm->next_out - state->x.next);
+ if (strm->sha256_ret == Z_SHA256_STATE_ACTIVE) {
+ if (0 != mbedtls_sha256_update(&(strm->sha256_context), state->x.next, put)) {
+ strm->sha256_ret = Z_SHA256_STATE_ERROR;
+ }
+ }
writ = write(state->fd, state->x.next, put);
if (writ < 0) {
gz_error(state, Z_ERRNO, zstrerror());
@@ -591,6 +601,89 @@ int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
return Z_OK;
}
+/**
+* Get the SHA-256 hash and free the hash structure.
+*
+* Returns 0 on success and -1 on error
+*/
+local int gz_getSha256(gzFile file, unsigned char hashBuf[32]) {
+
+ memset(hashBuf, 0, 32);
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ if (state->strm.sha256_ret == Z_SHA256_STATE_UNINITIALIZED) {
+ return -1;
+ }
+
+ if (state->strm.sha256_ret == Z_SHA256_STATE_ERROR) {
+ mbedtls_sha256_free(&(state->strm.sha256_context));
+ return -1;
+ }
+
+ if (0 != mbedtls_sha256_finish(&(state->strm.sha256_context), hashBuf)) {
+ mbedtls_sha256_free(&(state->strm.sha256_context));
+ return -1;
+ }
+
+ mbedtls_sha256_free(&(state->strm.sha256_context));
+ state->strm.sha256_ret = Z_SHA256_STATE_UNINITIALIZED;
+ return 0;
+}
+
+/**
+* Copy of normal gzclose_w but calculates and returns the SHA-256 hash of the compressed data
+* and the number of bytes written.
+*/
+ZEXTERN int ZEXPORT gzclose_hash_w(gzFile file, unsigned char hashBuf[32], z_off64_t* compressedSize) {
+ int ret = Z_OK;
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ /* check that we're writing */
+ if (state->mode != GZ_WRITE)
+ return Z_STREAM_ERROR;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ ret = state->err;
+ }
+
+ /* flush */
+ if (gz_comp(state, Z_FINISH) == -1)
+ ret = state->err;
+
+ /* At this point all data has been written to the file but nothing is closed so
+ we can calculate and store the hash and file size. */
+ gz_getSha256(file, hashBuf);
+ *compressedSize = gzoffset64(file);
+
+ /* free memory and close file */
+ if (state->size) {
+ if (!state->direct) {
+ (void)deflateEnd(&(state->strm));
+ free(state->out);
+ }
+ free(state->in);
+ }
+ gz_error(state, Z_OK, NULL);
+ free(state->path);
+ if (close(state->fd) == -1)
+ ret = Z_ERRNO;
+ free(state);
+ return ret;
+}
+
/* -- see zlib.h -- */
int ZEXPORT gzclose_w(gzFile file) {
int ret = Z_OK;
@@ -629,3 +722,4 @@ int ZEXPORT gzclose_w(gzFile file) {
free(state);
return ret;
}
+
diff --git a/zlib.h b/zlib.h
index 8d4b932eaf..1fcb9d0fef 100644
--- a/zlib.h
+++ b/zlib.h
@@ -32,6 +32,7 @@
#define ZLIB_H
#include "zconf.h"
+#include "mbedtls/sha256.h"
#ifdef __cplusplus
extern "C" {
@@ -103,6 +104,8 @@ typedef struct z_stream_s {
for deflate, or the decoding state for inflate */
uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */
uLong reserved; /* reserved for future use */
+ mbedtls_sha256_context sha256_context;
+ int sha256_ret;
} z_stream;
typedef z_stream FAR *z_streamp;
@@ -1646,6 +1649,7 @@ ZEXTERN int ZEXPORT gzclose(gzFile file);
ZEXTERN int ZEXPORT gzclose_r(gzFile file);
ZEXTERN int ZEXPORT gzclose_w(gzFile file);
+ZEXTERN int ZEXPORT gzclose_hash_w(gzFile file, unsigned char hashBuf[32], z_off64_t* compressedSize);
/*
Same as gzclose(), but gzclose_r() is only for use when reading, and
gzclose_w() is only for use when writing or appending. The advantage to
@@ -1931,6 +1935,12 @@ ZEXTERN int ZEXPORTVA gzvprintf(gzFile file,
# endif
#endif
+#define Z_SHA256_STATE_UNINITIALIZED 0 // Not enabled, finished, or an error occurred during initialization. Do not need to free structure.
+#define Z_SHA256_STATE_ACTIVE 1 // Actively hashing data
+#define Z_SHA256_STATE_ERROR 2 // An error occurred so no longer hashing data. Structure still must be freed
+ZEXTERN void ZEXPORT gz_hash_init(gzFile file);
+ZEXTERN int ZEXPORT gzclose_hash(gzFile file, unsigned char hashBuf[32], z_off64_t* compressedSize);
+
#ifdef __cplusplus
}
#endif