diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index 473ec2201..e4512876a 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -91,7 +91,7 @@ SOURCES += subsurface-mobile-main.cpp \ core/gas.c \ core/membuffer.cpp \ core/selection.cpp \ - core/sha1.c \ + core/sha1.cpp \ core/string-format.cpp \ core/strtod.cpp \ core/tag.cpp \ diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 944b0a604..e4883dd83 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -162,7 +162,7 @@ set(SUBSURFACE_CORE_LIB_SRCS save-xml.cpp selection.cpp selection.h - sha1.c + sha1.cpp sha1.h ssrf.h statistics.c diff --git a/core/divesite.cpp b/core/divesite.cpp index 7b7e419b0..5c23b2f22 100644 --- a/core/divesite.cpp +++ b/core/divesite.cpp @@ -138,18 +138,14 @@ extern "C" int add_dive_site_to_table(struct dive_site *ds, struct dive_site_tab /* If the site doesn't yet have an UUID, create a new one. * Make this deterministic for testing. */ if (!ds->uuid) { - SHA_CTX ctx; - uint32_t csum[5]; - - SHA1_Init(&ctx); + SHA1 sha; if (ds->name) - SHA1_Update(&ctx, ds->name, strlen(ds->name)); + sha.update(ds->name, strlen(ds->name)); if (ds->description) - SHA1_Update(&ctx, ds->description, strlen(ds->description)); + sha.update(ds->description, strlen(ds->description)); if (ds->notes) - SHA1_Update(&ctx, ds->notes, strlen(ds->notes)); - SHA1_Final((unsigned char *)csum, &ctx); - ds->uuid = csum[0]; + sha.update(ds->notes, strlen(ds->notes)); + ds->uuid = sha.hash_uint32(); } /* Take care to never have the same uuid twice. This could happen on diff --git a/core/git-access.cpp b/core/git-access.cpp index 1c9678c98..ca22659bb 100644 --- a/core/git-access.cpp +++ b/core/git-access.cpp @@ -135,9 +135,6 @@ std::string normalize_cloud_name(const std::string &remote_in) std::string get_local_dir(const std::string &url, const std::string &branch) { - SHA_CTX ctx; - unsigned char hash[20]; - // this optimization could in theory lead to odd things happening if the // cloud backend servers ever get out of sync - but when a user switches // between those servers (either because one is down, or because the algorithm @@ -148,11 +145,11 @@ std::string get_local_dir(const std::string &url, const std::string &branch) // That zero-byte update is so that we don't get hash // collisions for "repo1 branch" vs "repo 1branch". - SHA1_Init(&ctx); - SHA1_Update(&ctx, remote.c_str(), remote.size()); - SHA1_Update(&ctx, "", 1); - SHA1_Update(&ctx, branch.c_str(), branch.size()); - SHA1_Final(hash, &ctx); + SHA1 sha; + sha.update(remote); + sha.update("", 1); + sha.update(branch); + auto hash = sha.hash(); return format_string_std("%s/cloudstorage/%02x%02x%02x%02x%02x%02x%02x%02x", system_default_directory(), hash[0], hash[1], hash[2], hash[3], diff --git a/core/sha1.c b/core/sha1.cpp similarity index 87% rename from core/sha1.c rename to core/sha1.cpp index 09da8da3f..04bf13b6e 100644 --- a/core/sha1.c +++ b/core/sha1.cpp @@ -8,7 +8,6 @@ /* this is only to get definitions for memcpy(), ntohl() and htonl() */ #include -#include #ifdef WIN32 #include #else @@ -132,16 +131,16 @@ #define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B &C) + (D &(B ^ C))), 0x8f1bbcdc, A, B, C, D, E) #define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B ^ C ^ D), 0xca62c1d6, A, B, C, D, E) -static void blk_SHA1_Block(blk_SHA_CTX *ctx, const void *block) +static void blk_SHA1_Block(unsigned int H[], const void *block) { unsigned int A, B, C, D, E; unsigned int array[16]; - A = ctx->H[0]; - B = ctx->H[1]; - C = ctx->H[2]; - D = ctx->H[3]; - E = ctx->H[4]; + A = H[0]; + B = H[1]; + C = H[2]; + D = H[3]; + E = H[4]; /* Round 1 - iterations 0-16 take their input from 'block' */ T_0_15(0, A, B, C, D, E); @@ -233,80 +232,84 @@ static void blk_SHA1_Block(blk_SHA_CTX *ctx, const void *block) T_60_79(78, C, D, E, A, B); T_60_79(79, B, C, D, E, A); - ctx->H[0] += A; - ctx->H[1] += B; - ctx->H[2] += C; - ctx->H[3] += D; - ctx->H[4] += E; + H[0] += A; + H[1] += B; + H[2] += C; + H[3] += D; + H[4] += E; } -void blk_SHA1_Init(blk_SHA_CTX *ctx) -{ - ctx->size = 0; - +SHA1::SHA1() : + size(0), /* Initialize H with the magic constants (see FIPS180 for constants) */ - ctx->H[0] = 0x67452301; - ctx->H[1] = 0xefcdab89; - ctx->H[2] = 0x98badcfe; - ctx->H[3] = 0x10325476; - ctx->H[4] = 0xc3d2e1f0; + H { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 } +{ } -void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len) +void SHA1::update(const void *data, unsigned long len) { - unsigned int lenW = ctx->size & 63; + unsigned int lenW = size & 63; - ctx->size += len; + size += len; /* Read the data into W and process blocks as they get full */ if (lenW) { unsigned int left = 64 - lenW; if (len < left) left = len; - memcpy(lenW + (char *)ctx->W, data, left); + memcpy(lenW + (char *)W, data, left); lenW = (lenW + left) & 63; len -= left; data = ((const char *)data + left); if (lenW) return; - blk_SHA1_Block(ctx, ctx->W); + blk_SHA1_Block(H, W); } while (len >= 64) { - blk_SHA1_Block(ctx, data); + blk_SHA1_Block(H, data); data = ((const char *)data + 64); len -= 64; } if (len) - memcpy(ctx->W, data, len); + memcpy(W, data, len); } -void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx) +void SHA1::update(const std::string &s) { + update(s.data(), s.size()); +} + +std::array SHA1::hash() +{ + std::array hashout; static const unsigned char pad[64] = { 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)); + padlen[0] = htonl((uint32_t)(size >> 29)); + padlen[1] = htonl((uint32_t)(size << 3)); - i = ctx->size & 63; - blk_SHA1_Update(ctx, pad, 1 + (63 & (55 - i))); - blk_SHA1_Update(ctx, padlen, 8); + i = size & 63; + update(pad, 1 + (63 & (55 - i))); + update(padlen, 8); /* Output hash */ for (i = 0; i < 5; i++) - put_be32(hashout + i * 4, ctx->H[i]); + put_be32(&hashout[i * 4], H[i]); + return hashout; +} + +uint32_t SHA1::hash_uint32() +{ + auto hashout = hash(); + return (hashout[0] << 0) | (hashout[1] << 8) | + (hashout[2] << 16) | (hashout[3] << 24); } uint32_t SHA1_uint32(const void *dataIn, unsigned long len) { - uint32_t hashout[5]; - SHA_CTX ctx; - - SHA1_Init(&ctx); - SHA1_Update(&ctx, dataIn, len); - SHA1_Final((unsigned char *)hashout, &ctx); - - return hashout[0]; + SHA1 sha; + sha.update(dataIn, len); + return sha.hash_uint32(); } diff --git a/core/sha1.h b/core/sha1.h index 341d9231f..4fbb4629a 100644 --- a/core/sha1.h +++ b/core/sha1.h @@ -9,31 +9,28 @@ #define SHA1_H #ifdef __cplusplus -extern "C" { -#endif -typedef struct +#include +#include + +struct SHA1 { + SHA1(); + void update(const void *dataIn, unsigned long len); + void update(const std::string &s); + // Note: the hash() functions change state. Call only once. + std::array hash(); + uint32_t hash_uint32(); // Return first 4 bytes of hash interpreted + // as little-endian unsigned integer. +private: unsigned long long size; unsigned int H[5]; unsigned int W[16]; -} blk_SHA_CTX; - -void blk_SHA1_Init(blk_SHA_CTX *ctx); -void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, unsigned long len); -void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx); - -/* Make us use the standard names */ -#define SHA_CTX blk_SHA_CTX -#define SHA1_Init blk_SHA1_Init -#define SHA1_Update blk_SHA1_Update -#define SHA1_Final blk_SHA1_Final +}; /* Helper function that calculates an SHA1 has and returns the first 4 bytes as uint32_t */ uint32_t SHA1_uint32(const void *dataIn, unsigned long len); -#ifdef __cplusplus -} #endif #endif // SHA1_H