mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 06:28:19 +00:00
Merge pull request #2055 from heinrich5991/pr_sha256
Use more secure hash function for map downloads
This commit is contained in:
commit
ac6f1ac506
|
@ -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 $<$<CONFIG:Debug>: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})
|
||||
|
|
19
cmake/FindCrypto.cmake
Normal file
19
cmake/FindCrypto.cmake
Normal file
|
@ -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()
|
41
src/base/hash.c
Normal file
41
src/base/hash.c
Normal file
|
@ -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));
|
||||
}
|
43
src/base/hash.h
Normal file
43
src/base/hash.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef BASE_HASH_H
|
||||
#define BASE_HASH_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#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
|
35
src/base/hash_ctxt.h
Normal file
35
src/base/hash_ctxt.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef BASE_HASH_CTXT_H
|
||||
#define BASE_HASH_CTXT_H
|
||||
|
||||
#include "hash.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(CONF_OPENSSL)
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(CONF_OPENSSL)
|
||||
// SHA256_CTX is defined in <openssl/sha.h>
|
||||
#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
|
197
src/base/hash_libtomcrypt.c
Executable file
197
src/base/hash_libtomcrypt.c
Executable file
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
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
|
20
src/base/hash_openssl.c
Normal file
20
src/base/hash_openssl.c
Normal file
|
@ -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
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef ENGINE_CLIENT_CLIENT_H
|
||||
#define ENGINE_CLIENT_CLIENT_H
|
||||
|
||||
#include <base/hash.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#ifndef ENGINE_MAP_H
|
||||
#define ENGINE_MAP_H
|
||||
|
||||
#include <base/hash.h>
|
||||
#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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <base/hash_ctxt.h>
|
||||
#include <base/math.h>
|
||||
#include <base/system.h>
|
||||
#include <engine/storage.h>
|
||||
|
@ -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;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef ENGINE_SHARED_DATAFILE_H
|
||||
#define ENGINE_SHARED_DATAFILE_H
|
||||
|
||||
#include <base/hash.h>
|
||||
|
||||
// raw datafile access
|
||||
class CDataFileReader
|
||||
{
|
||||
|
@ -30,6 +32,7 @@ public:
|
|||
int NumData() const;
|
||||
void Unload();
|
||||
|
||||
SHA256_DIGEST Sha256() const;
|
||||
unsigned Crc() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -86,6 +86,11 @@ public:
|
|||
return m_DataFile.IsOpen();
|
||||
}
|
||||
|
||||
virtual SHA256_DIGEST Sha256()
|
||||
{
|
||||
return m_DataFile.Sha256();
|
||||
}
|
||||
|
||||
virtual unsigned Crc()
|
||||
{
|
||||
return m_DataFile.Crc();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef ENGINE_SHARED_MAPCHECKER_H
|
||||
#define ENGINE_SHARED_MAPCHECKER_H
|
||||
|
||||
#include <base/hash.h>
|
||||
|
||||
#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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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 <base/hash_ctxt.h>
|
||||
#include <base/system.h>
|
||||
#include <engine/storage.h>
|
||||
#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;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#ifndef ENGINE_STORAGE_H
|
||||
#define ENGINE_STORAGE_H
|
||||
|
||||
#include <base/hash.h>
|
||||
#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);
|
||||
|
|
42
src/test/hash.cpp
Normal file
42
src/test/hash.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <base/hash_ctxt.h>
|
||||
#include <base/system.h>
|
||||
|
||||
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));
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue