From 12fcb172632502a49da2a9bcfbe12705d30cab74 Mon Sep 17 00:00:00 2001 From: apriestman Date: Mon, 22 Dec 2025 15:02:32 -0500 Subject: [PATCH] Add sha-256 hashing --- contrib/vstudio/vc17/zlibstat.vcxproj | 6 +- gzclose.c | 32 +++++++++ gzlib.c | 2 + gzwrite.c | 94 +++++++++++++++++++++++++++ zlib.h | 10 +++ 5 files changed, 142 insertions(+), 2 deletions(-) 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