From b986e540393c4677aef04583ad3b99b23d501ab4 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Wed, 6 Mar 2019 15:30:57 +0100 Subject: [PATCH 1/2] Add the SHA256 cryptographic hash function Use the OpenSSL implementation of SHA256 if it is supported, otherwise fall back to a public domain one. --- CMakeLists.txt | 13 ++- cmake/FindCrypto.cmake | 19 ++++ src/base/hash.c | 41 ++++++++ src/base/hash.h | 43 ++++++++ src/base/hash_ctxt.h | 35 +++++++ src/base/hash_libtomcrypt.c | 197 ++++++++++++++++++++++++++++++++++++ src/base/hash_openssl.c | 20 ++++ src/test/hash.cpp | 42 ++++++++ 8 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 cmake/FindCrypto.cmake create mode 100644 src/base/hash.c create mode 100644 src/base/hash.h create mode 100644 src/base/hash_ctxt.h create mode 100755 src/base/hash_libtomcrypt.c create mode 100644 src/base/hash_openssl.c create mode 100644 src/test/hash.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fd12f0a53..44d156efa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -294,6 +294,7 @@ if(NOT CMAKE_CROSSCOMPILING) find_package(PkgConfig) endif() find_package(ZLIB) +find_package(Crypto) find_package(Freetype) find_package(Git) find_package(GTest) @@ -342,6 +343,7 @@ show_dependency_status("Freetype" FREETYPE) if(TARGET_OS AND TARGET_OS STREQUAL "mac") show_dependency_status("Hdiutil" HDIUTIL) endif() +show_dependency_status("OpenSSL Crypto" CRYPTO) show_dependency_status("Pnglite" PNGLITE) show_dependency_status("PythonInterp" PYTHONINTERP) show_dependency_status("SDL2" SDL2) @@ -1124,6 +1126,11 @@ generate_source("src/generated/server_data.h" "server_content_header") set_src(BASE GLOB_RECURSE src/base color.h detect.h + hash.c + hash.h + hash_ctxt.h + hash_libtomcrypt.c + hash_openssl.c math.h system.c system.h @@ -1231,7 +1238,7 @@ set(GAME_GENERATED_SHARED set(DEPS ${DEP_MD5} ${ZLIB_DEP}) # Libraries -set(LIBS ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES} ${PLATFORM_LIBS}) +set(LIBS ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES} ${CRYPTO_LIBRARIES} ${PLATFORM_LIBS}) # Targets add_library(engine-shared EXCLUDE_FROM_ALL OBJECT ${ENGINE_INTERFACE} ${ENGINE_SHARED} ${ENGINE_GENERATED_SHARED} ${BASE}) @@ -1561,6 +1568,7 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST) set_src(TESTS GLOB src/test fs.cpp git_revision.cpp + hash.cpp storage.cpp str.cpp test.cpp @@ -1951,6 +1959,9 @@ foreach(target ${TARGETS_OWN}) target_compile_definitions(${target} PRIVATE $<$:CONF_DEBUG>) target_include_directories(${target} PRIVATE ${CURL_INCLUDE_DIRS}) target_include_directories(${target} PRIVATE ${ZLIB_INCLUDE_DIRS}) + if(CRYPTO_FOUND) + target_compile_definitions(${target} PRIVATE CONF_OPENSSL) + endif() endforeach() foreach(target ${TARGETS_DEP}) diff --git a/cmake/FindCrypto.cmake b/cmake/FindCrypto.cmake new file mode 100644 index 000000000..f765e7157 --- /dev/null +++ b/cmake/FindCrypto.cmake @@ -0,0 +1,19 @@ +if(NOT PREFER_BUNDLED_LIBS) + find_package(OpenSSL) + if(OPENSSL_FOUND) + set(CRYPTO_FOUND ON) + set(CRYPTO_BUNDLED OFF) + set(CRYPTO_LIBRARY ${OPENSSL_CRYPTO_LIBRARY}) + set(CRYPTO_INCLUDEDIR ${OPENSSL_INCLUDE_DIR}) + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Crypto DEFAULT_MSG CRYPTO_LIBRARY CRYPTO_INCLUDEDIR) + +mark_as_advanced(CRYPTO_LIBRARY CRYPTO_INCLUDEDIR) + +if(CRYPTO_FOUND) + set(CRYPTO_LIBRARIES ${CRYPTO_LIBRARY}) + set(CRYPTO_INCLUDE_DIRS ${CRYPTO_INCLUDEDIR}) +endif() diff --git a/src/base/hash.c b/src/base/hash.c new file mode 100644 index 000000000..eb2f20587 --- /dev/null +++ b/src/base/hash.c @@ -0,0 +1,41 @@ +#include "hash.h" +#include "hash_ctxt.h" + +#include "system.h" + +SHA256_DIGEST sha256(const void *message, size_t message_len) +{ + SHA256_CTX ctxt; + sha256_init(&ctxt); + sha256_update(&ctxt, message, message_len); + return sha256_finish(&ctxt); +} + +void sha256_str(SHA256_DIGEST digest, char *str, size_t max_len) +{ + unsigned i; + if(max_len > SHA256_MAXSTRSIZE) + { + max_len = SHA256_MAXSTRSIZE; + } + str[max_len - 1] = 0; + max_len -= 1; + for(i = 0; i < max_len; i++) + { + static const char HEX[] = "0123456789abcdef"; + int index = i / 2; + if(i % 2 == 0) + { + str[i] = HEX[digest.data[index] >> 4]; + } + else + { + str[i] = HEX[digest.data[index] & 0xf]; + } + } +} + +int sha256_comp(SHA256_DIGEST digest1, SHA256_DIGEST digest2) +{ + return mem_comp(digest1.data, digest2.data, sizeof(digest1.data)); +} diff --git a/src/base/hash.h b/src/base/hash.h new file mode 100644 index 000000000..cdb947bd1 --- /dev/null +++ b/src/base/hash.h @@ -0,0 +1,43 @@ +#ifndef BASE_HASH_H +#define BASE_HASH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + SHA256_DIGEST_LENGTH=256/8, + SHA256_MAXSTRSIZE=2*SHA256_DIGEST_LENGTH+1, +}; + +typedef struct +{ + unsigned char data[SHA256_DIGEST_LENGTH]; +} SHA256_DIGEST; + +SHA256_DIGEST sha256(const void *message, size_t message_len); +void sha256_str(SHA256_DIGEST digest, char *str, size_t max_len); +int sha256_from_str(SHA256_DIGEST *out, const char *str); +int sha256_comp(SHA256_DIGEST digest1, SHA256_DIGEST digest2); + +static const SHA256_DIGEST SHA256_ZEROED = {{0}}; + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +inline bool operator==(const SHA256_DIGEST &that, const SHA256_DIGEST &other) +{ + return sha256_comp(that, other) == 0; +} +inline bool operator!=(const SHA256_DIGEST &that, const SHA256_DIGEST &other) +{ + return !(that == other); +} +#endif + +#endif // BASE_HASH_H diff --git a/src/base/hash_ctxt.h b/src/base/hash_ctxt.h new file mode 100644 index 000000000..636ed6741 --- /dev/null +++ b/src/base/hash_ctxt.h @@ -0,0 +1,35 @@ +#ifndef BASE_HASH_CTXT_H +#define BASE_HASH_CTXT_H + +#include "hash.h" +#include + +#if defined(CONF_OPENSSL) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(CONF_OPENSSL) +// SHA256_CTX is defined in +#else +typedef struct +{ + uint64_t length; + uint32_t state[8]; + uint32_t curlen; + unsigned char buf[64]; +} SHA256_CTX; +#endif + +void sha256_init(SHA256_CTX *ctxt); +void sha256_update(SHA256_CTX *ctxt, const void *data, size_t data_len); +SHA256_DIGEST sha256_finish(SHA256_CTX *ctxt); + +#ifdef __cplusplus +} +#endif + +#endif // BASE_HASH_CTXT_H diff --git a/src/base/hash_libtomcrypt.c b/src/base/hash_libtomcrypt.c new file mode 100755 index 000000000..b249f27e0 --- /dev/null +++ b/src/base/hash_libtomcrypt.c @@ -0,0 +1,197 @@ +// SHA-256. Adapted from https://github.com/kalven/sha-2, which was adapted +// from LibTomCrypt. This code is Public Domain. + +#if !defined(CONF_OPENSSL) + +#include "hash_ctxt.h" + +#include +#include +#include + +typedef uint32_t u32; +typedef uint64_t u64; +typedef SHA256_CTX sha256_state; + +static const u32 K[64] = +{ + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +static u32 min(u32 x, u32 y) +{ + return x < y ? x : y; +} + +static u32 load32(const unsigned char* y) +{ + return ((u32)y[0] << 24) | ((u32)y[1] << 16) | ((u32)y[2] << 8) | ((u32)y[3] << 0); +} + +static void store64(u64 x, unsigned char* y) +{ + for(int i = 0; i != 8; ++i) + y[i] = (x >> ((7-i) * 8)) & 255; +} + +static void store32(u32 x, unsigned char* y) +{ + for(int i = 0; i != 4; ++i) + y[i] = (x >> ((3-i) * 8)) & 255; +} + +static u32 Ch(u32 x, u32 y, u32 z) { return z ^ (x & (y ^ z)); } +static u32 Maj(u32 x, u32 y, u32 z) { return ((x | y) & z) | (x & y); } +static u32 Rot(u32 x, u32 n) { return (x >> (n & 31)) | (x << (32 - (n & 31))); } +static u32 Sh(u32 x, u32 n) { return x >> n; } +static u32 Sigma0(u32 x) { return Rot(x, 2) ^ Rot(x, 13) ^ Rot(x, 22); } +static u32 Sigma1(u32 x) { return Rot(x, 6) ^ Rot(x, 11) ^ Rot(x, 25); } +static u32 Gamma0(u32 x) { return Rot(x, 7) ^ Rot(x, 18) ^ Sh(x, 3); } +static u32 Gamma1(u32 x) { return Rot(x, 17) ^ Rot(x, 19) ^ Sh(x, 10); } + +static void sha_compress(sha256_state* md, const unsigned char* buf) +{ + u32 S[8], W[64], t0, t1, t; + + // Copy state into S + for(int i = 0; i < 8; i++) + S[i] = md->state[i]; + + // Copy the state into 512-bits into W[0..15] + for(int i = 0; i < 16; i++) + W[i] = load32(buf + (4*i)); + + // Fill W[16..63] + for(int i = 16; i < 64; i++) + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + + // Compress + #define RND(a, b, c, d, e, f, g, h, i) \ + { \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; \ + } + + for(int i = 0; i < 64; ++i) + { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + // Feedback + for(int i = 0; i < 8; i++) + md->state[i] = md->state[i] + S[i]; +} + +// Public interface + +static void sha_init(sha256_state* md) +{ + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; +} + +static void sha_process(sha256_state* md, const void* src, u32 inlen) +{ + const u32 block_size = 64; + const unsigned char* in = src; + + while(inlen > 0) + { + if(md->curlen == 0 && inlen >= block_size) + { + sha_compress(md, in); + md->length += block_size * 8; + in += block_size; + inlen -= block_size; + } + else + { + u32 n = min(inlen, (block_size - md->curlen)); + memcpy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + + if(md->curlen == block_size) + { + sha_compress(md, md->buf); + md->length += 8*block_size; + md->curlen = 0; + } + } + } +} + +static void sha_done(sha256_state* md, void* out) +{ + // Increase the length of the message + md->length += md->curlen * 8; + + // Append the '1' bit + md->buf[md->curlen++] = (unsigned char)0x80; + + // If the length is currently above 56 bytes we append zeros then compress. + // Then we can fall back to padding zeros and length encoding like normal. + if(md->curlen > 56) + { + while(md->curlen < 64) + md->buf[md->curlen++] = 0; + sha_compress(md, md->buf); + md->curlen = 0; + } + + // Pad upto 56 bytes of zeroes + while(md->curlen < 56) + md->buf[md->curlen++] = 0; + + // Store length + store64(md->length, md->buf+56); + sha_compress(md, md->buf); + + // Copy output + for(int i = 0; i < 8; i++) + store32(md->state[i], (unsigned char *)out+(4*i)); +} + +void sha256_init(SHA256_CTX *ctxt) +{ + sha_init(ctxt); +} + +void sha256_update(SHA256_CTX *ctxt, const void *data, size_t data_len) +{ + sha_process(ctxt, data, data_len); +} + +SHA256_DIGEST sha256_finish(SHA256_CTX *ctxt) +{ + SHA256_DIGEST result; + sha_done(ctxt, result.data); + return result; +} + +#endif diff --git a/src/base/hash_openssl.c b/src/base/hash_openssl.c new file mode 100644 index 000000000..6d2240abb --- /dev/null +++ b/src/base/hash_openssl.c @@ -0,0 +1,20 @@ +#if defined(CONF_OPENSSL) +#include "hash_ctxt.h" + +void sha256_init(SHA256_CTX *ctxt) +{ + SHA256_Init(ctxt); +} + +void sha256_update(SHA256_CTX *ctxt, const void *data, size_t data_len) +{ + SHA256_Update(ctxt, data, data_len); +} + +SHA256_DIGEST sha256_finish(SHA256_CTX *ctxt) +{ + SHA256_DIGEST result; + SHA256_Final(result.data, ctxt); + return result; +} +#endif diff --git a/src/test/hash.cpp b/src/test/hash.cpp new file mode 100644 index 000000000..7a018e215 --- /dev/null +++ b/src/test/hash.cpp @@ -0,0 +1,42 @@ +#include + +#include +#include + +static void Expect(SHA256_DIGEST Actual, const char *pWanted) +{ + char aActual[SHA256_MAXSTRSIZE]; + sha256_str(Actual, aActual, sizeof(aActual)); + EXPECT_STREQ(aActual, pWanted); +} + +TEST(Hash, Sha256) +{ + // https://en.wikipedia.org/w/index.php?title=SHA-2&oldid=840187620#Test_vectors + Expect(sha256("", 0), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + SHA256_CTX ctxt; + + sha256_init(&ctxt); + Expect(sha256_finish(&ctxt), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + + // printf 'The quick brown fox jumps over the lazy dog.' | sha256sum + char QUICK_BROWN_FOX[] = "The quick brown fox jumps over the lazy dog."; + Expect(sha256(QUICK_BROWN_FOX, str_length(QUICK_BROWN_FOX)), "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"); + + sha256_init(&ctxt); + sha256_update(&ctxt, "The ", 4); + sha256_update(&ctxt, "quick ", 6); + sha256_update(&ctxt, "brown ", 6); + sha256_update(&ctxt, "fox ", 4); + sha256_update(&ctxt, "jumps ", 6); + sha256_update(&ctxt, "over ", 5); + sha256_update(&ctxt, "the ", 4); + sha256_update(&ctxt, "lazy ", 5); + sha256_update(&ctxt, "dog.", 4); + Expect(sha256_finish(&ctxt), "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"); +} + +TEST(Hash, Sha256Eq) +{ + EXPECT_EQ(sha256("", 0), sha256("", 0)); +} From 1f0b2f6ee50e50a8bfd5b70f39f1368a06e03d3c Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Fri, 8 Mar 2019 18:59:20 +0100 Subject: [PATCH 2/2] Use more secure hash function for map downloads SHA256 was chosen because it is reasonably standard, the file names don't explode in length (this rules out SHA512) and it is supported by basically all versions of OpenSSL (this rules out SHA512/256 and SHA3). The protocol is changed in a backward compatible way: The supporting server sends the SHA256 corresponding to the map in the `MAP_CHANGE` message after the previously known fields. For servers not supporting this protocol, the client falls back to simply opening maps like in the previous scheme. The filename scheme for downloaded maps changed from `{name}_{crc}.map` to `{name}_{sha256}.map` if the SHA256 is known, otherwise it falls back to the previous scheme. Fixes #1691. --- src/engine/client/client.cpp | 83 ++++++++++++++++++++++++++------ src/engine/client/client.h | 9 +++- src/engine/map.h | 2 + src/engine/server/server.cpp | 12 +++-- src/engine/server/server.h | 1 + src/engine/shared/datafile.cpp | 15 +++++- src/engine/shared/datafile.h | 3 ++ src/engine/shared/demo.cpp | 4 +- src/engine/shared/demo.h | 2 +- src/engine/shared/map.cpp | 5 ++ src/engine/shared/mapchecker.cpp | 2 +- src/engine/shared/mapchecker.h | 5 +- src/engine/shared/storage.cpp | 25 +++++++--- src/engine/storage.h | 5 +- src/test/storage.cpp | 21 +++++--- 15 files changed, 151 insertions(+), 43 deletions(-) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index f1fca781d..ef4d4f7f5 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -277,6 +277,7 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD // m_aCurrentMap[0] = 0; + m_CurrentMapSha256 = SHA256_ZEROED; m_CurrentMapCrc = 0; // @@ -287,6 +288,8 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD m_aMapdownloadName[0] = 0; m_MapdownloadFile = 0; m_MapdownloadChunk = 0; + m_MapdownloadSha256 = SHA256_ZEROED; + m_MapdownloadSha256Present = false; m_MapdownloadCrc = 0; m_MapdownloadAmount = -1; m_MapdownloadTotalsize = -1; @@ -545,6 +548,8 @@ void CClient::DisconnectWithReason(const char *pReason) if(m_MapdownloadFile) io_close(m_MapdownloadFile); m_MapdownloadFile = 0; + m_MapdownloadSha256 = SHA256_ZEROED; + m_MapdownloadSha256Present = false; m_MapdownloadCrc = 0; m_MapdownloadTotalsize = -1; m_MapdownloadAmount = 0; @@ -756,9 +761,9 @@ void CClient::Render() DebugRender(); } -const char *CClient::LoadMap(const char *pName, const char *pFilename, unsigned WantedCrc) +const char *CClient::LoadMap(const char *pName, const char *pFilename, const SHA256_DIGEST *pWantedSha256, unsigned WantedCrc) { - static char aErrorMsg[128]; + static char aErrorMsg[512]; SetState(IClient::STATE_LOADING); @@ -768,6 +773,18 @@ const char *CClient::LoadMap(const char *pName, const char *pFilename, unsigned return aErrorMsg; } + if(pWantedSha256 && m_pMap->Sha256() != *pWantedSha256) + { + char aSha256[SHA256_MAXSTRSIZE]; + char aWantedSha256[SHA256_MAXSTRSIZE]; + sha256_str(m_pMap->Sha256(), aSha256, sizeof(aSha256)); + sha256_str(*pWantedSha256, aWantedSha256, sizeof(aWantedSha256)); + str_format(aErrorMsg, sizeof(aErrorMsg), "map differs from the server. %s != %s", aSha256, aWantedSha256); + m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aErrorMsg); + m_pMap->Unload(); + return aErrorMsg; + } + // get the crc of the map if(m_pMap->Crc() != WantedCrc) { @@ -786,38 +803,70 @@ const char *CClient::LoadMap(const char *pName, const char *pFilename, unsigned m_RecivedSnapshots = 0; str_copy(m_aCurrentMap, pName, sizeof(m_aCurrentMap)); + m_CurrentMapSha256 = m_pMap->Sha256(); m_CurrentMapCrc = m_pMap->Crc(); return 0x0; } +static void FormatMapDownloadFilename(const char *pName, const SHA256_DIGEST *pSha256, int Crc, char *pBuffer, int BufferSize) +{ + if(pSha256) + { + char aSha256[SHA256_MAXSTRSIZE]; + sha256_str(*pSha256, aSha256, sizeof(aSha256)); + str_format(pBuffer, BufferSize, "downloadedmaps/%s_%s.map", pName, aSha256); + } + else + { + str_format(pBuffer, BufferSize, "downloadedmaps/%s_%08x.map", pName, Crc); + } +} -const char *CClient::LoadMapSearch(const char *pMapName, int WantedCrc) + +const char *CClient::LoadMapSearch(const char *pMapName, const SHA256_DIGEST *pWantedSha256, int WantedCrc) { const char *pError = 0; char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "loading map, map=%s wanted crc=%08x", pMapName, WantedCrc); + char aWanted[SHA256_MAXSTRSIZE + 16]; + aWanted[0] = 0; + if(pWantedSha256) + { + char aWantedSha256[SHA256_MAXSTRSIZE]; + sha256_str(*pWantedSha256, aWantedSha256, sizeof(aWantedSha256)); + str_format(aWanted, sizeof(aWanted), "sha256=%s ", aWantedSha256); + } + str_format(aBuf, sizeof(aBuf), "loading map, map=%s wanted %scrc=%08x", pMapName, aWanted, WantedCrc); m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf); SetState(IClient::STATE_LOADING); // try the normal maps folder str_format(aBuf, sizeof(aBuf), "maps/%s.map", pMapName); - pError = LoadMap(pMapName, aBuf, WantedCrc); + pError = LoadMap(pMapName, aBuf, pWantedSha256, WantedCrc); if(!pError) return pError; // try the downloaded maps - str_format(aBuf, sizeof(aBuf), "downloadedmaps/%s_%08x.map", pMapName, WantedCrc); - pError = LoadMap(pMapName, aBuf, WantedCrc); + FormatMapDownloadFilename(pMapName, pWantedSha256, WantedCrc, aBuf, sizeof(aBuf)); + pError = LoadMap(pMapName, aBuf, pWantedSha256, WantedCrc); if(!pError) return pError; + // backward compatibility with old names + if(pWantedSha256) + { + FormatMapDownloadFilename(pMapName, 0, WantedCrc, aBuf, sizeof(aBuf)); + pError = LoadMap(pMapName, aBuf, 0, WantedCrc); + if(!pError) + return pError; + } + // search for the map within subfolders char aFilename[128]; str_format(aFilename, sizeof(aFilename), "%s.map", pMapName); if(Storage()->FindFile(aFilename, "maps", IStorage::TYPE_ALL, aBuf, sizeof(aBuf))) - pError = LoadMap(pMapName, aBuf, WantedCrc); + pError = LoadMap(pMapName, aBuf, pWantedSha256, WantedCrc); return pError; } @@ -1023,13 +1072,13 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) int MapSize = Unpacker.GetInt(); int MapChunkNum = Unpacker.GetInt(); int MapChunkSize = Unpacker.GetInt(); - const char *pError = 0; - if(Unpacker.Error()) return; + const SHA256_DIGEST *pMapSha256 = (const SHA256_DIGEST *)Unpacker.GetRaw(sizeof(*pMapSha256)); + const char *pError = 0; // check for valid standard map - if(!m_MapChecker.IsMapValid(pMap, MapCrc, MapSize)) + if(!m_MapChecker.IsMapValid(pMap, pMapSha256, MapCrc, MapSize)) pError = "invalid standard map"; // protect the player from nasty map names @@ -1046,7 +1095,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) DisconnectWithReason(pError); else { - pError = LoadMapSearch(pMap, MapCrc); + pError = LoadMapSearch(pMap, pMapSha256, MapCrc); if(!pError) { @@ -1056,7 +1105,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) else { // start map download - str_format(m_aMapdownloadFilename, sizeof(m_aMapdownloadFilename), "downloadedmaps/%s_%08x.map", pMap, MapCrc); + FormatMapDownloadFilename(pMap, pMapSha256, MapCrc, m_aMapdownloadFilename, sizeof(m_aMapdownloadFilename)); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "starting to download map to '%s'", m_aMapdownloadFilename); @@ -1069,6 +1118,8 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) m_MapdownloadChunk = 0; m_MapdownloadChunkNum = MapChunkNum; m_MapDownloadChunkSize = MapChunkSize; + m_MapdownloadSha256 = pMapSha256 ? *pMapSha256 : SHA256_ZEROED; + m_MapdownloadSha256Present = pMapSha256; m_MapdownloadCrc = MapCrc; m_MapdownloadTotalsize = MapSize; m_MapdownloadAmount = 0; @@ -1108,7 +1159,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) m_MapdownloadTotalsize = -1; // load map - const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, m_MapdownloadCrc); + const char *pError = LoadMap(m_aMapdownloadName, m_aMapdownloadFilename, m_MapdownloadSha256Present ? &m_MapdownloadSha256 : 0, m_MapdownloadCrc); if(!pError) { m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/network", "loading done"); @@ -2184,7 +2235,7 @@ const char *CClient::DemoPlayer_Play(const char *pFilename, int StorageType) (m_DemoPlayer.Info()->m_Header.m_aMapCrc[1]<<16)| (m_DemoPlayer.Info()->m_Header.m_aMapCrc[2]<<8)| (m_DemoPlayer.Info()->m_Header.m_aMapCrc[3]); - pError = LoadMapSearch(m_DemoPlayer.Info()->m_Header.m_aMapName, Crc); + pError = LoadMapSearch(m_DemoPlayer.Info()->m_Header.m_aMapName, 0, Crc); if(pError) { DisconnectWithReason(pError); @@ -2239,7 +2290,7 @@ void CClient::DemoRecorder_Start(const char *pFilename, bool WithTimestamp) } else str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pFilename); - m_DemoRecorder.Start(Storage(), m_pConsole, aFilename, GameClient()->NetVersion(), m_aCurrentMap, m_CurrentMapCrc, "client"); + m_DemoRecorder.Start(Storage(), m_pConsole, aFilename, GameClient()->NetVersion(), m_aCurrentMap, m_CurrentMapSha256, m_CurrentMapCrc, "client"); } } diff --git a/src/engine/client/client.h b/src/engine/client/client.h index c6609df52..6888c0fa2 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -3,6 +3,8 @@ #ifndef ENGINE_CLIENT_CLIENT_H #define ENGINE_CLIENT_CLIENT_H +#include + class CGraph { public: @@ -114,6 +116,7 @@ class CClient : public IClient, public CDemoPlayer::IListner // char m_aCurrentMap[256]; + SHA256_DIGEST m_CurrentMapSha256; unsigned m_CurrentMapCrc; // @@ -126,6 +129,8 @@ class CClient : public IClient, public CDemoPlayer::IListner int m_MapdownloadChunk; int m_MapdownloadChunkNum; int m_MapDownloadChunkSize; + SHA256_DIGEST m_MapdownloadSha256; + bool m_MapdownloadSha256Present; int m_MapdownloadCrc; int m_MapdownloadAmount; int m_MapdownloadTotalsize; @@ -252,8 +257,8 @@ public: virtual const char *ErrorString() const; - const char *LoadMap(const char *pName, const char *pFilename, unsigned WantedCrc); - const char *LoadMapSearch(const char *pMapName, int WantedCrc); + const char *LoadMap(const char *pName, const char *pFilename, const SHA256_DIGEST *pWantedSha256, unsigned WantedCrc); + const char *LoadMapSearch(const char *pMapName, const SHA256_DIGEST *pWantedSha256, int WantedCrc); int UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pToken); void ProcessConnlessPacket(CNetChunk *pPacket); diff --git a/src/engine/map.h b/src/engine/map.h index 5e0809831..bdc3cc68f 100644 --- a/src/engine/map.h +++ b/src/engine/map.h @@ -3,6 +3,7 @@ #ifndef ENGINE_MAP_H #define ENGINE_MAP_H +#include #include "kernel.h" class IMap : public IInterface @@ -26,6 +27,7 @@ public: virtual bool Load(const char *pMapName, class IStorage *pStorage=0) = 0; virtual bool IsLoaded() = 0; virtual void Unload() = 0; + virtual SHA256_DIGEST Sha256() = 0; virtual unsigned Crc() = 0; }; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index f2be35f73..613dc6b99 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -714,6 +714,7 @@ void CServer::SendMap(int ClientID) Msg.AddInt(m_CurrentMapSize); Msg.AddInt(m_MapChunksPerRequest); Msg.AddInt(MAP_CHUNK_SIZE); + Msg.AddRaw(&m_CurrentMapSha256, sizeof(m_CurrentMapSha256)); SendMsg(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID); } @@ -1242,9 +1243,14 @@ int CServer::LoadMap(const char *pMapName) // reinit snapshot ids m_IDPool.TimeoutIDs(); - // get the crc of the map + // get the sha256 and crc of the map + m_CurrentMapSha256 = m_pMap->Sha256(); m_CurrentMapCrc = m_pMap->Crc(); + char aSha256[SHA256_MAXSTRSIZE]; + sha256_str(m_CurrentMapSha256, aSha256, sizeof(aSha256)); char aBufMsg[256]; + str_format(aBufMsg, sizeof(aBufMsg), "%s sha256 is %s", aBuf, aSha256); + Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBufMsg); str_format(aBufMsg, sizeof(aBufMsg), "%s crc is %08x", aBuf, m_CurrentMapCrc); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBufMsg); @@ -1560,7 +1566,7 @@ void CServer::DemoRecorder_HandleAutoStart() char aDate[20]; str_timestamp(aDate, sizeof(aDate)); str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", "auto/autorecord", aDate); - m_DemoRecorder.Start(Storage(), m_pConsole, aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapCrc, "server"); + m_DemoRecorder.Start(Storage(), m_pConsole, aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapSha256, m_CurrentMapCrc, "server"); if(g_Config.m_SvAutoDemoMax) { // clean up auto recorded demos @@ -1587,7 +1593,7 @@ void CServer::ConRecord(IConsole::IResult *pResult, void *pUser) str_timestamp(aDate, sizeof(aDate)); str_format(aFilename, sizeof(aFilename), "demos/demo_%s.demo", aDate); } - pServer->m_DemoRecorder.Start(pServer->Storage(), pServer->Console(), aFilename, pServer->GameServer()->NetVersion(), pServer->m_aCurrentMap, pServer->m_CurrentMapCrc, "server"); + pServer->m_DemoRecorder.Start(pServer->Storage(), pServer->Console(), aFilename, pServer->GameServer()->NetVersion(), pServer->m_aCurrentMap, pServer->m_CurrentMapSha256, pServer->m_CurrentMapCrc, "server"); } void CServer::ConStopRecord(IConsole::IResult *pResult, void *pUser) diff --git a/src/engine/server/server.h b/src/engine/server/server.h index f792d9744..9ff0d2c6c 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -163,6 +163,7 @@ public: MAP_CHUNK_SIZE=NET_MAX_PAYLOAD-NET_MAX_CHUNKHEADERSIZE-4, // msg type }; char m_aCurrentMap[64]; + SHA256_DIGEST m_CurrentMapSha256; unsigned m_CurrentMapCrc; unsigned char *m_pCurrentMapData; int m_CurrentMapSize; diff --git a/src/engine/shared/datafile.cpp b/src/engine/shared/datafile.cpp index aaa6e9f39..1310559c3 100644 --- a/src/engine/shared/datafile.cpp +++ b/src/engine/shared/datafile.cpp @@ -1,5 +1,6 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include #include #include #include @@ -58,6 +59,7 @@ struct CDatafileInfo struct CDatafile { IOHANDLE m_File; + SHA256_DIGEST m_Sha256; unsigned m_Crc; CDatafileInfo m_Info; CDatafileHeader m_Header; @@ -78,7 +80,9 @@ bool CDataFileReader::Open(class IStorage *pStorage, const char *pFilename, int } - // take the CRC of the file and store it + // take the hashes of the file and store them + SHA256_CTX Sha256Ctx; + sha256_init(&Sha256Ctx); unsigned Crc = crc32(0L, 0x0, 0); { enum @@ -93,13 +97,13 @@ bool CDataFileReader::Open(class IStorage *pStorage, const char *pFilename, int unsigned Bytes = io_read(File, aBuffer, BUFFER_SIZE); if(Bytes <= 0) break; + sha256_update(&Sha256Ctx, aBuffer, Bytes); Crc = crc32(Crc, aBuffer, Bytes); // ignore_convention } io_seek(File, 0, IOSEEK_START); } - // TODO: change this header CDatafileHeader Header; io_read(File, &Header, sizeof(Header)); @@ -141,6 +145,7 @@ bool CDataFileReader::Open(class IStorage *pStorage, const char *pFilename, int pTmpDataFile->m_ppDataPtrs = (char**)(pTmpDataFile+1); pTmpDataFile->m_pData = (char *)(pTmpDataFile+1)+Header.m_NumRawData*sizeof(char *); pTmpDataFile->m_File = File; + pTmpDataFile->m_Sha256 = sha256_finish(&Sha256Ctx); pTmpDataFile->m_Crc = Crc; // clear the data pointers @@ -401,6 +406,12 @@ bool CDataFileReader::Close() return true; } +SHA256_DIGEST CDataFileReader::Sha256() const +{ + if(!m_pDataFile) return SHA256_ZEROED; + return m_pDataFile->m_Sha256; +} + unsigned CDataFileReader::Crc() const { if(!m_pDataFile) return 0xFFFFFFFF; diff --git a/src/engine/shared/datafile.h b/src/engine/shared/datafile.h index 2e8044d61..72286cf7e 100644 --- a/src/engine/shared/datafile.h +++ b/src/engine/shared/datafile.h @@ -3,6 +3,8 @@ #ifndef ENGINE_SHARED_DATAFILE_H #define ENGINE_SHARED_DATAFILE_H +#include + // raw datafile access class CDataFileReader { @@ -30,6 +32,7 @@ public: int NumData() const; void Unload(); + SHA256_DIGEST Sha256() const; unsigned Crc() const; }; diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index c1a3162f9..dda2e444c 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -25,8 +25,10 @@ CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta) m_pSnapshotDelta = pSnapshotDelta; } +// TODO: fix demo map loading (looks broken) + // Record -int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetVersion, const char *pMap, unsigned Crc, const char *pType) +int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetVersion, const char *pMap, SHA256_DIGEST Sha256, unsigned Crc, const char *pType) { CDemoHeader Header; if(m_File) diff --git a/src/engine/shared/demo.h b/src/engine/shared/demo.h index 1bdc3f9a0..8d3671dad 100644 --- a/src/engine/shared/demo.h +++ b/src/engine/shared/demo.h @@ -25,7 +25,7 @@ class CDemoRecorder : public IDemoRecorder public: CDemoRecorder(class CSnapshotDelta *pSnapshotDelta); - int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, unsigned MapCrc, const char *pType); + int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc, const char *pType); int Stop(); void AddDemoMarker(); diff --git a/src/engine/shared/map.cpp b/src/engine/shared/map.cpp index f49e682d2..d38bab669 100644 --- a/src/engine/shared/map.cpp +++ b/src/engine/shared/map.cpp @@ -86,6 +86,11 @@ public: return m_DataFile.IsOpen(); } + virtual SHA256_DIGEST Sha256() + { + return m_DataFile.Sha256(); + } + virtual unsigned Crc() { return m_DataFile.Crc(); diff --git a/src/engine/shared/mapchecker.cpp b/src/engine/shared/mapchecker.cpp index 24098715c..9eaf0ffd3 100644 --- a/src/engine/shared/mapchecker.cpp +++ b/src/engine/shared/mapchecker.cpp @@ -46,7 +46,7 @@ void CMapChecker::AddMaplist(CMapVersion *pMaplist, int Num) } } -bool CMapChecker::IsMapValid(const char *pMapName, unsigned MapCrc, unsigned MapSize) +bool CMapChecker::IsMapValid(const char *pMapName, const SHA256_DIGEST *pMapSha256, unsigned MapCrc, unsigned MapSize) { return true; /*bool StandardMap = false; diff --git a/src/engine/shared/mapchecker.h b/src/engine/shared/mapchecker.h index 8f6d24e8e..72668b9d5 100644 --- a/src/engine/shared/mapchecker.h +++ b/src/engine/shared/mapchecker.h @@ -3,6 +3,8 @@ #ifndef ENGINE_SHARED_MAPCHECKER_H #define ENGINE_SHARED_MAPCHECKER_H +#include + #include "memheap.h" class CMapChecker @@ -15,6 +17,7 @@ class CMapChecker struct CWhitelistEntry { char m_aMapName[MAX_MAP_LENGTH]; + SHA256_DIGEST m_MapSha256; unsigned m_MapCrc; unsigned m_MapSize; CWhitelistEntry *m_pNext; @@ -31,7 +34,7 @@ class CMapChecker public: CMapChecker(); void AddMaplist(struct CMapVersion *pMaplist, int Num); - bool IsMapValid(const char *pMapName, unsigned MapCrc, unsigned MapSize); + bool IsMapValid(const char *pMapName, const SHA256_DIGEST *pMapSha256, unsigned MapCrc, unsigned MapSize); bool ReadAndValidateMap(class IStorage *pStorage, const char *pFilename, int StorageType); }; diff --git a/src/engine/shared/storage.cpp b/src/engine/shared/storage.cpp index 4f60342ba..db010980b 100644 --- a/src/engine/shared/storage.cpp +++ b/src/engine/shared/storage.cpp @@ -1,5 +1,6 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include #include #include #include "linereader.h" @@ -342,9 +343,10 @@ public: const char *m_pPath; char *m_pBuffer; int m_BufferSize; + const SHA256_DIGEST *m_pWantedSha256; unsigned m_WantedCrc; unsigned m_WantedSize; - bool m_CheckCrcSize; + bool m_CheckHashAndSize; }; static int FindFileCallback(const char *pName, int IsDir, int Type, void *pUser) @@ -369,12 +371,13 @@ public: // found the file str_format(Data.m_pBuffer, Data.m_BufferSize, "%s/%s", Data.m_pPath, Data.m_pFilename); - if(Data.m_CheckCrcSize) + if(Data.m_CheckHashAndSize) { // check crc and size + SHA256_DIGEST Sha256; unsigned Crc = 0; unsigned Size = 0; - if(!Data.m_pStorage->GetCrcSize(Data.m_pBuffer, Type, &Crc, &Size) || Crc != Data.m_WantedCrc || Size != Data.m_WantedSize) + if(!Data.m_pStorage->GetHashAndSize(Data.m_pBuffer, Type, &Sha256, &Crc, &Size) || (Data.m_pWantedSha256 && Sha256 != *Data.m_pWantedSha256) || Crc != Data.m_WantedCrc || Size != Data.m_WantedSize) { Data.m_pBuffer[0] = 0; return 0; @@ -423,13 +426,14 @@ public: Data.m_pPath = pPath; Data.m_pBuffer = pBuffer; Data.m_BufferSize = BufferSize; + Data.m_pWantedSha256 = 0; Data.m_WantedCrc = 0; Data.m_WantedSize = 0; - Data.m_CheckCrcSize = false; + Data.m_CheckHashAndSize = false; return FindFileImpl(Type, &Data); } - virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize, unsigned WantedCrc, unsigned WantedSize) + virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize, const SHA256_DIGEST *pWantedSha256, unsigned WantedCrc, unsigned WantedSize) { CFindCBData Data; Data.m_pStorage = this; @@ -437,9 +441,10 @@ public: Data.m_pPath = pPath; Data.m_pBuffer = pBuffer; Data.m_BufferSize = BufferSize; + Data.m_pWantedSha256 = pWantedSha256; Data.m_WantedCrc = WantedCrc; Data.m_WantedSize = WantedSize; - Data.m_CheckCrcSize = true; + Data.m_CheckHashAndSize = true; return FindFileImpl(Type, &Data); } @@ -482,13 +487,15 @@ public: GetPath(Type, pDir, pBuffer, BufferSize); } - virtual bool GetCrcSize(const char *pFilename, int StorageType, unsigned *pCrc, unsigned *pSize) + virtual bool GetHashAndSize(const char *pFilename, int StorageType, SHA256_DIGEST *pSha256, unsigned *pCrc, unsigned *pSize) { IOHANDLE File = OpenFile(pFilename, IOFLAG_READ, StorageType); if(!File) return false; - // get crc and size + // get hash and size + SHA256_CTX Sha256Ctx; + sha256_init(&Sha256Ctx); unsigned Crc = 0; unsigned Size = 0; unsigned char aBuffer[64*1024]; @@ -497,12 +504,14 @@ public: unsigned Bytes = io_read(File, aBuffer, sizeof(aBuffer)); if(Bytes <= 0) break; + sha256_update(&Sha256Ctx, aBuffer, Bytes); Crc = crc32(Crc, aBuffer, Bytes); // ignore_convention Size += Bytes; } io_close(File); + *pSha256 = sha256_finish(&Sha256Ctx); *pCrc = Crc; *pSize = Size; return true; diff --git a/src/engine/storage.h b/src/engine/storage.h index e9a9f71aa..2833de069 100644 --- a/src/engine/storage.h +++ b/src/engine/storage.h @@ -3,6 +3,7 @@ #ifndef ENGINE_STORAGE_H #define ENGINE_STORAGE_H +#include #include "kernel.h" class IStorage : public IInterface @@ -22,12 +23,12 @@ public: virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) = 0; virtual IOHANDLE OpenFile(const char *pFilename, int Flags, int Type, char *pBuffer = 0, int BufferSize = 0) = 0; virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize) = 0; - virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize, unsigned WantedCrc, unsigned WantedSize) = 0; + virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize, const SHA256_DIGEST *pWantedSha256, unsigned WantedCrc, unsigned WantedSize) = 0; virtual bool RemoveFile(const char *pFilename, int Type) = 0; virtual bool RenameFile(const char* pOldFilename, const char* pNewFilename, int Type) = 0; virtual bool CreateFolder(const char *pFoldername, int Type) = 0; virtual void GetCompletePath(int Type, const char *pDir, char *pBuffer, unsigned BufferSize) = 0; - virtual bool GetCrcSize(const char *pFilename, int StorageType, unsigned *pCrc, unsigned *pSize) = 0; + virtual bool GetHashAndSize(const char *pFilename, int StorageType, SHA256_DIGEST *pSha256, unsigned *pCrc, unsigned *pSize) = 0; }; IStorage *CreateStorage(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments); diff --git a/src/test/storage.cpp b/src/test/storage.cpp index 992137909..a42906284 100644 --- a/src/test/storage.cpp +++ b/src/test/storage.cpp @@ -16,17 +16,26 @@ TEST(Storage, FindFile) EXPECT_EQ(io_write(File, "test\n", 5), 5); EXPECT_FALSE(io_close(File)); + SHA256_DIGEST Sha256 = sha256("test\n", 5); + SHA256_DIGEST WrongSha256 = sha256("", 0); + char aFound[128]; EXPECT_TRUE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound))); EXPECT_STREQ(aFound, aFilenameWithDot); - EXPECT_TRUE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0x3bb935c6, 5)); + EXPECT_TRUE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0x3bb935c6, 5)); EXPECT_STREQ(aFound, aFilenameWithDot); - EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0)); - EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0x3bb935c6, 0)); - EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 5)); - EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0x3bb935c5, 5)); - EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0x3bb935c6, 6)); + EXPECT_TRUE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &Sha256, 0x3bb935c6, 5)); + EXPECT_STREQ(aFound, aFilenameWithDot); + + EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0, 0)); + EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0x3bb935c6, 0)); + EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0, 5)); + EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0x3bb935c5, 5)); + EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0x3bb935c6, 6)); + + EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &WrongSha256, 0x3bb935c6, 5)); + EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &SHA256_ZEROED, 0x3bb935c6, 5)); }