From c5f837d468b97ce3c7cbd7e2a3c5e171b6f30b9f Mon Sep 17 00:00:00 2001 From: Shpoike Date: Mon, 20 Feb 2023 06:13:40 +0000 Subject: [PATCH] Rework some hashfunc_t stuff. --- engine/client/cl_demo.c | 4 +- engine/client/cl_main.c | 16 +-- engine/client/m_download.c | 4 +- engine/client/pr_csqc.c | 2 +- engine/client/sys_linux.c | 2 +- engine/common/cmd.c | 2 +- engine/common/common.h | 19 ++-- engine/common/fs.c | 8 +- engine/common/fs_dzip.c | 4 +- engine/common/fs_pak.c | 4 +- engine/common/fs_zip.c | 4 +- engine/common/gl_q2bsp.c | 2 +- engine/common/md4.c | 55 +++------ engine/common/net_ice.c | 68 +++++++----- engine/common/plugin.c | 7 +- engine/common/pr_bgcmd.c | 21 ++-- engine/common/sha1.c | 2 +- engine/common/sha2.c | 8 +- engine/gl/gl_model.c | 4 +- engine/server/pr_cmds.c | 2 +- engine/server/sv_init.c | 2 +- engine/server/sv_mvd.c | 202 ++++++++++------------------------ fteqtv/qtv.h | 8 +- fteqtv/source.c | 2 +- plugins/jabber/jabberclient.c | 8 +- plugins/plugin.h | 2 +- 26 files changed, 184 insertions(+), 278 deletions(-) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 470026916..6f8887151 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -3009,9 +3009,9 @@ fail: else if (!strcmp(auth, "SHA1")) hashfunc = &hash_sha1; else if (!strcmp(auth, "SHA2_256")) - hashfunc = &hash_sha256; + hashfunc = &hash_sha2_256; else if (!strcmp(auth, "SHA2_512")) - hashfunc = &hash_sha512; + hashfunc = &hash_sha2_512; else if (*auth) Con_Printf("Server requires unsupported auth method: %s\n", auth); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 7bc15cafa..93d318829 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -536,10 +536,9 @@ char *CL_GUIDString(netadr_t *adr) { static qbyte buf[2048]; static int buflen; - unsigned int digest[4]; + qbyte digest[DIGEST_MAXSIZE]; char serveraddr[256]; - void *blocks[2]; - int lens[2]; + void *ctx; if (!*cl_sendguid.string && *connectinfo.ext.guidsalt) { @@ -587,11 +586,12 @@ char *CL_GUIDString(netadr_t *adr) } } - blocks[0] = buf;lens[0] = buflen; - blocks[1] = serveraddr;lens[1] = strlen(serveraddr); - Com_BlocksChecksum(2, blocks, lens, (void*)digest); - - Q_snprintfz(connectinfo.guid, sizeof(connectinfo.guid), "%08x%08x%08x%08x", digest[0], digest[1], digest[2], digest[3]); + ctx = alloca(hash_md4.contextsize); + hash_md4.init(ctx); + hash_md4.process(ctx, buf, buflen); + hash_md4.process(ctx, serveraddr, strlen(serveraddr)); + hash_md4.terminate(digest, ctx); + Base16_EncodeBlock(digest, hash_md4.digestsize, connectinfo.guid, sizeof(connectinfo.guid)); return connectinfo.guid; } diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 8e8235d3a..68ebb4edf 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -1498,7 +1498,7 @@ static qboolean PM_ParsePackageList(const char *f, unsigned int parseflags, cons size_t signsize; enum hashvalidation_e r; int i; - hashfunc_t *hf = &hash_sha512; + hashfunc_t *hf = &hash_sha2_512; void *hashdata = Z_Malloc(hf->digestsize); void *hashctx = Z_Malloc(hf->contextsize); tokstart = COM_StringParse (tokstart, authority, sizeof(authority), false, false); @@ -4071,7 +4071,7 @@ static void PM_StartADownload(void) } if (p->filesha512 && tmpfile) - tmpfile = FS_Hash_ValidateWrites(tmpfile, p->name, p->filesize, &hash_sha512, p->filesha512); + tmpfile = FS_Hash_ValidateWrites(tmpfile, p->name, p->filesize, &hash_sha2_512, p->filesha512); else if (p->filesha1 && tmpfile) tmpfile = FS_Hash_ValidateWrites(tmpfile, p->name, p->filesize, &hash_sha1, p->filesha1); diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 53ea4d0bc..c749d8ea9 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -7997,7 +7997,7 @@ static qboolean CSQC_ValidateMainCSProgs(void *file, size_t filesize, unsigned i } else { //FTE uses folded-md4. yeah, its broken but at least its still more awkward - if (LittleLong(Com_BlockChecksum(file, filesize)) != checksum) + if (LittleLong(CalcHashInt(&hash_md4, file, filesize)) != checksum) return false; } return true; diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 407afa06a..19c4146b5 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -1219,7 +1219,7 @@ static void DoSign(const char *fname, int signtype) } else if (f) { - hashfunc_t *h = (signtype==1)?&hash_sha256:&hash_sha512; + hashfunc_t *h = (signtype==1)?&hash_sha2_256:&hash_sha2_512; size_t l, ts = 0; void *ctx = alloca(h->contextsize); qbyte data[65536*16]; diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 9da9b9fba..b9da841c4 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -916,7 +916,7 @@ static void Cmd_Exec_f (void) Cbuf_InsertText (fs_manifest->defaultoverrides, level, false); #if defined(HAVE_LEGACY) && defined(HAVE_CLIENT) - if (l == 1914 && Com_BlockChecksum(f, l) == 0x2d7b72b9) + if (l == 1914 && CalcHashInt(&hash_md4, f, l) == 0x2d7b72b9) s = (char*)replacementq1binds; #endif } diff --git a/engine/common/common.h b/engine/common/common.h index a744998b9..99ad87262 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -930,14 +930,12 @@ void InfoBuf_WriteToFile(vfsfile_t *f, infobuf_t *info, const char *commandname, void InfoBuf_Enumerate (infobuf_t *info, void *ctx, void(*cb)(void *ctx, const char *key, const char *value)); -void Com_BlocksChecksum (int blocks, void **buffer, int *len, unsigned char *outbuf); -unsigned int Com_BlockChecksum (const void *buffer, int length); -void Com_BlockFullChecksum (const void *buffer, int len, unsigned char *outbuf); qbyte COM_BlockSequenceCheckByte (qbyte *base, int length, int sequence, unsigned mapchecksum); qbyte COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence); qbyte Q2COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence); size_t Base64_EncodeBlock(const qbyte *in, size_t length, char *out, size_t outsize); //tries to null terminate, but returns length without termination. +size_t Base64_EncodeBlockURI(const qbyte *in, size_t length, char *out, size_t outsize); //slightly different chars for uri safety. also trims. size_t Base64_DecodeBlock(const char *in, const char *in_end, qbyte *out, size_t outsize); // +/ and = size_t Base16_EncodeBlock(const char *in, size_t length, qbyte *out, size_t outsize); size_t Base16_DecodeBlock(const char *in, qbyte *out, size_t outsize); @@ -951,15 +949,16 @@ typedef struct void (*process) (void *context, const void *data, size_t datasize); void (*terminate) (unsigned char *digest, void *context); } hashfunc_t; -extern hashfunc_t hash_sha1; -extern hashfunc_t hash_sha224; -extern hashfunc_t hash_sha256; -extern hashfunc_t hash_sha384; -extern hashfunc_t hash_sha512; -extern hashfunc_t hash_crc16; +extern hashfunc_t hash_md4; //required for vanilla qw mapchecks +extern hashfunc_t hash_sha1; //required for websockets, and ezquake's crypted rcon +extern hashfunc_t hash_sha2_224; +extern hashfunc_t hash_sha2_256; //required for webrtc +extern hashfunc_t hash_sha2_384; +extern hashfunc_t hash_sha2_512; +extern hashfunc_t hash_crc16; //aka ccitt, required for qw's clc_move and various bits of dp compat extern hashfunc_t hash_crc16_lower; unsigned int hashfunc_terminate_uint(const hashfunc_t *hash, void *context); //terminate, except returning the digest as a uint instead of a blob. folds the digest if longer than 4 bytes. -unsigned int CalcHashInt(const hashfunc_t *hash, const unsigned char *data, size_t datasize); +unsigned int CalcHashInt(const hashfunc_t *hash, const void *data, size_t datasize); size_t CalcHash(const hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datasize); size_t CalcHMAC(const hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datalen, const unsigned char *key, size_t keylen); diff --git a/engine/common/fs.c b/engine/common/fs.c index 87ee87c93..c605bb632 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1330,10 +1330,10 @@ static void COM_CalcHash_Thread(void *ctx, void *fname, size_t a, size_t b) // {"crc16", &hash_crc16}, {"sha1", &hash_sha1}, #if defined(HAVE_SERVER) || defined(HAVE_CLIENT) -// {"sha224", &hash_sha224}, - {"sha256", &hash_sha256}, -// {"sha384", &hash_sha384}, -// {"sha512", &hash_sha512}, +// {"sha224", &hash_sha2_224}, + {"sha256", &hash_sha2_256}, +// {"sha384", &hash_sha2_384}, +// {"sha512", &hash_sha2_512}, #endif }; qbyte digest[DIGEST_MAXSIZE]; diff --git a/engine/common/fs_dzip.c b/engine/common/fs_dzip.c index f2dd74f67..1f9a43fd6 100644 --- a/engine/common/fs_dzip.c +++ b/engine/common/fs_dzip.c @@ -1235,9 +1235,9 @@ static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int c } if (crctype) - result = Com_BlockChecksum(filecrcs, numcrcs*sizeof(int)); + result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int)); else - result = Com_BlockChecksum(filecrcs+1, (numcrcs-1)*sizeof(int)); + result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int)); BZ_Free(filecrcs); return result; diff --git a/engine/common/fs_pak.c b/engine/common/fs_pak.c index 6817c2adf..de306ca0d 100644 --- a/engine/common/fs_pak.c +++ b/engine/common/fs_pak.c @@ -176,9 +176,9 @@ static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int } if (crctype) - result = Com_BlockChecksum(filecrcs, numcrcs*sizeof(int)); + result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int)); else - result = Com_BlockChecksum(filecrcs+1, (numcrcs-1)*sizeof(int)); + result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int)); BZ_Free(filecrcs); return result; diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 8fcd51712..fcb771327 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -788,9 +788,9 @@ static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int } if (crctype || numcrcs < 1) - result = Com_BlockChecksum(filecrcs, numcrcs*sizeof(int)); + result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int)); else - result = Com_BlockChecksum(filecrcs+1, (numcrcs-1)*sizeof(int)); + result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int)); BZ_Free(filecrcs); return result; diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index ce5a05748..5f59cd587 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -4517,7 +4517,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole return NULL; } - checksum = LittleLong (Com_BlockChecksum (buf, length)); + checksum = LittleLong (CalcHashInt(&hash_md4, buf, length)); header = *(q2dheader_t *)(buf); header.ident = LittleLong(header.ident); diff --git a/engine/common/md4.c b/engine/common/md4.c index 0e08ff9cd..4edb246f0 100644 --- a/engine/common/md4.c +++ b/engine/common/md4.c @@ -51,7 +51,7 @@ typedef struct { } MD4_CTX; void MD4Init (MD4_CTX *); -void MD4Update (MD4_CTX *, unsigned char *, unsigned int); +void MD4Update (MD4_CTX *, const unsigned char *, size_t); void MD4Final (unsigned char [16], MD4_CTX *); @@ -84,9 +84,9 @@ These notices must be retained in any copies of any part of this documentation a #define S33 11 #define S34 15 -static void MD4Transform (UINT4 [4], unsigned char [64]); +static void MD4Transform (UINT4 [4], const unsigned char [64]); static void Encode (unsigned char *, UINT4 *, unsigned int); -static void Decode (UINT4 *, unsigned char *, unsigned int); +static void Decode (UINT4 *, const unsigned char *, unsigned int); static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 @@ -122,7 +122,7 @@ context->state[3] = 0x10325476; } /* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */ -void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen) +void MD4Update (MD4_CTX *context, const unsigned char *input, size_t inputLen) { unsigned int i, index, partLen; @@ -182,7 +182,7 @@ void MD4Final (unsigned char digest[16], MD4_CTX *context) /* MD4 basic transformation. Transforms state based on block. */ -static void MD4Transform (UINT4 state[4], unsigned char block[64]) +static void MD4Transform (UINT4 state[4], const unsigned char block[64]) { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; @@ -267,7 +267,7 @@ static void Encode (unsigned char *output, UINT4 *input, unsigned int len) /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ -static void Decode (UINT4 *output, unsigned char *input, unsigned int len) +static void Decode (UINT4 *output, const unsigned char *input, unsigned int len) { unsigned int i, j; @@ -276,40 +276,13 @@ for (i = 0, j = 0; j < len; i++, j += 4) } //=================================================================== - -unsigned int Com_BlockChecksum (void *buffer, int length) +#include "quakedef.h" +hashfunc_t hash_md4 = { - unsigned int digest[4]; - unsigned int val; - MD4_CTX ctx; + 16, //digest size + sizeof(MD4_CTX), + (void(*)(void*ctx))MD4Init, + (void(*)(void*ctx,const void*in,size_t))MD4Update, + (void(*)(qbyte*out,void*ctx))MD4Final, +}; - MD4Init (&ctx); - MD4Update (&ctx, (unsigned char *)buffer, length); - MD4Final ( (unsigned char *)digest, &ctx); - - val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3]; - - return val; -} - -void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf) -{ - MD4_CTX ctx; - - MD4Init (&ctx); - MD4Update (&ctx, (unsigned char *)buffer, len); - MD4Final ( outbuf, &ctx); -} - - -void Com_BlocksChecksum (int blocks, void **buffer, int *len, unsigned char *outbuf) -{ - MD4_CTX ctx; - - MD4Init (&ctx); - while(blocks --> 0) - { - MD4Update (&ctx, (unsigned char *)*buffer++, *len++); - } - MD4Final (outbuf, &ctx); -} diff --git a/engine/common/net_ice.c b/engine/common/net_ice.c index 78088baf5..64a0a01a7 100644 --- a/engine/common/net_ice.c +++ b/engine/common/net_ice.c @@ -256,6 +256,21 @@ typedef struct sctp_s unsigned short qstreamid; //in network endian. } sctp_t; #ifdef HAVE_DTLS + +static const struct +{ + const char *name; + hashfunc_t *hash; +} webrtc_hashes[] = +{ //RFC8211 specifies this list of hashes +// {"md2", &hash_md2}, //deprecated, hopefully we won't see it +// {"md5", &hash_md5}, //deprecated, hopefully we won't see it + {"sha-1", &hash_sha1}, + {"sha-224", &hash_sha2_224}, + {"sha-256", &hash_sha2_256}, + {"sha-384", &hash_sha2_384}, + {"sha-512", &hash_sha2_512}, +}; extern cvar_t net_enable_dtls; static neterr_t SCTP_Transmit(sctp_t *sctp, struct icestate_s *peer, const void *data, size_t length); #endif @@ -1912,26 +1927,24 @@ static void ICE_ParseSDPLine(struct icestate_s *con, const char *value) } else if (!strncmp(value, "a=fingerprint:", 14)) { + hashfunc_t *hash = NULL; + int i; char name[64]; value = COM_ParseOut(value+14, name, sizeof(name)); - if (!strcasecmp(name, "sha-1")) - con->cred.peer.hash = &hash_sha1; - else if (!strcasecmp(name, "sha-224")) - con->cred.peer.hash = &hash_sha224; - else if (!strcasecmp(name, "sha-256")) - con->cred.peer.hash = &hash_sha256; - else if (!strcasecmp(name, "sha-384")) - con->cred.peer.hash = &hash_sha384; - else if (!strcasecmp(name, "sha-512")) - con->cred.peer.hash = &hash_sha512; - else - con->cred.peer.hash = NULL; //hash not recognised - if (con->cred.peer.hash) + for (i = 0; i < countof(webrtc_hashes); i++) + { + if (!strcasecmp(name, webrtc_hashes[i].name)) + { + hash = webrtc_hashes[i].hash; + break; + } + } + if (hash && (!con->cred.peer.hash || hash->digestsize>con->cred.peer.hash->digestsize)) //FIXME: digest size is not a good indicator of whether its exploitable or not, but should work for sha1/sha2 options. the sender here is expected to be trustworthy anyway. { int b, o, v; while (*value == ' ') value++; - for (b = 0; b < con->cred.peer.hash->digestsize; ) + for (b = 0; b < hash->digestsize; ) { v = *value; if (v >= '0' && v <= '9') @@ -1958,8 +1971,10 @@ static void ICE_ParseSDPLine(struct icestate_s *con, const char *value) break; value++; } - if (b != con->cred.peer.hash->digestsize) - con->cred.peer.hash = NULL; //bad! + if (b == hash->digestsize) + con->cred.peer.hash = hash; //it was the right size, woo. + else + con->cred.peer.hash = NULL; //bad! (should we 0-pad?) } } else if (!strncmp(value, "a=sctp-port:", 12)) @@ -2471,14 +2486,12 @@ static qboolean QDECL ICE_Get(struct icestate_s *con, const char *prop, char *va { int b; Q_strncatz(value, "a=fingerprint:", valuelen); - if (con->cred.peer.hash == &hash_sha1) - Q_strncatz(value, "sha-1", valuelen); - else if (con->cred.peer.hash == &hash_sha256) - Q_strncatz(value, "sha-256", valuelen); - else if (con->cred.peer.hash == &hash_sha512) - Q_strncatz(value, "sha-512", valuelen); - else - Q_strncatz(value, "UNKNOWN", valuelen); + for (b = 0; b < countof(webrtc_hashes); b++) + { + if (con->cred.peer.hash == webrtc_hashes[b].hash) + break; + } + Q_strncatz(value, (b==countof(webrtc_hashes))?"UNKNOWN":webrtc_hashes[b].name, valuelen); for (b = 0; b < con->cred.peer.hash->digestsize; b++) Q_strncatz(value, va(b?":%02X":" %02X", con->cred.peer.digest[b]), valuelen); Q_strncatz(value, "\n", valuelen); @@ -2533,16 +2546,17 @@ static qboolean QDECL ICE_Get(struct icestate_s *con, const char *prop, char *va { //this is a preliminary check to avoid wasting time if (!con->cred.local.certsize) return false; //fail if we cannot do dtls when its required. - if (!strcmp(prop, "sdpanswer") || !con->cred.peer.hash) + if (!strcmp(prop, "sdpanswer") && !con->cred.peer.hash) return false; //don't answer if they failed to provide a cert } if (con->cred.local.certsize) { qbyte fingerprint[DIGEST_MAXSIZE]; int b; - CalcHash(&hash_sha256, fingerprint, sizeof(fingerprint), con->cred.local.cert, con->cred.local.certsize); + hashfunc_t *hash = &hash_sha2_256; //browsers use sha-256, lets match them. + CalcHash(hash, fingerprint, sizeof(fingerprint), con->cred.local.cert, con->cred.local.certsize); Q_strncatz(value, "a=fingerprint:sha-256", valuelen); - for (b = 0; b < hash_sha256.digestsize; b++) + for (b = 0; b < hash->digestsize; b++) Q_strncatz(value, va(b?":%02X":" %02X", fingerprint[b]), valuelen); Q_strncatz(value, "\n", valuelen); diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 447e8ee21..a5f4004ff 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -1191,6 +1191,11 @@ void QDECL Plug_FS_EnumerateFiles(enum fs_relative fsroot, const char *match, in } } +unsigned int Plug_BlockChecksum(const void *data, size_t datasize) +{ //convienience function. we use md4 for legacy reasons (every qw engine must have an implementation) + return CalcHashInt(&hash_md4, data, datasize); +} + #if defined(HAVE_SERVER) && defined(HAVE_CLIENT) static qboolean QDECL Plug_MapLog_Query(const char *packagename, const char *mapname, float *vals) { @@ -1930,7 +1935,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s COM_GetFileExtension, COM_FileBase, COM_CleanUpPath, - Com_BlockChecksum, + Plug_BlockChecksum, FS_LoadMallocFile, FS_GetPackHashes, diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 91ee83671..f32a9abbb 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -5665,21 +5665,18 @@ static void QCBUILTIN PF_digest_internal (pubprogfuncs_t *prinst, struct globalv unsigned char hexdig[sizeof(digest)*2+1]; if (!strcmp(hashtype, "MD4")) - { - digestsize = 16; - Com_BlockFullChecksum(str, len, digest); - } + digestsize = CalcHash(&hash_md4, digest, sizeof(digest), str, len); //md5? else if (!strcmp(hashtype, "SHA1")) digestsize = CalcHash(&hash_sha1, digest, sizeof(digest), str, len); - else if (!strcmp(hashtype, "SHA224")) - digestsize = CalcHash(&hash_sha224, digest, sizeof(digest), str, len); - else if (!strcmp(hashtype, "SHA256")) - digestsize = CalcHash(&hash_sha256, digest, sizeof(digest), str, len); - else if (!strcmp(hashtype, "SHA384")) - digestsize = CalcHash(&hash_sha384, digest, sizeof(digest), str, len); - else if (!strcmp(hashtype, "SHA512")) - digestsize = CalcHash(&hash_sha512, digest, sizeof(digest), str, len); + else if (!strcmp(hashtype, "SHA2-224") || !strcmp(hashtype, "SHA224")) + digestsize = CalcHash(&hash_sha2_224, digest, sizeof(digest), str, len); + else if (!strcmp(hashtype, "SHA2-256") || !strcmp(hashtype, "SHA256")) + digestsize = CalcHash(&hash_sha2_256, digest, sizeof(digest), str, len); + else if (!strcmp(hashtype, "SHA2-384") || !strcmp(hashtype, "SHA384")) + digestsize = CalcHash(&hash_sha2_384, digest, sizeof(digest), str, len); + else if (!strcmp(hashtype, "SHA2-512") || !strcmp(hashtype, "SHA512")) + digestsize = CalcHash(&hash_sha2_512, digest, sizeof(digest), str, len); else if (!strcmp(hashtype, "CRC16")) digestsize = CalcHash(&hash_crc16, digest, sizeof(digest), str, len); else diff --git a/engine/common/sha1.c b/engine/common/sha1.c index 93000df2d..88ae464c4 100644 --- a/engine/common/sha1.c +++ b/engine/common/sha1.c @@ -194,7 +194,7 @@ unsigned int hashfunc_terminate_uint(const hashfunc_t *func, void *context) r ^= digest[l]<<((l%sizeof(r))*8); return r; } -unsigned int CalcHashInt(const hashfunc_t *func, const unsigned char *data, size_t datasize) +unsigned int CalcHashInt(const hashfunc_t *func, const void *data, size_t datasize) { void *ctx = alloca(func->contextsize); func->init(ctx); diff --git a/engine/common/sha2.c b/engine/common/sha2.c index f6a1e65de..a5069d38c 100644 --- a/engine/common/sha2.c +++ b/engine/common/sha2.c @@ -515,7 +515,7 @@ static void sha256_finish (qbyte *digest, void *context) memcpy(digest, hd->buf, 256/8); } -hashfunc_t hash_sha224 = +hashfunc_t hash_sha2_224 = { 224/8, sizeof(SHA2_CONTEXT), @@ -523,7 +523,7 @@ hashfunc_t hash_sha224 = sha2_write, sha224_finish }; -hashfunc_t hash_sha256 = +hashfunc_t hash_sha2_256 = { 256/8, sizeof(SHA2_CONTEXT), @@ -547,7 +547,7 @@ static void sha512_finish (qbyte *digest, void *context) memcpy(digest, hd->buf, 512/8); } -hashfunc_t hash_sha384 = +hashfunc_t hash_sha2_384 = { 384/8, sizeof(SHA2_CONTEXT), @@ -555,7 +555,7 @@ hashfunc_t hash_sha384 = sha2_write, sha384_finish }; -hashfunc_t hash_sha512 = +hashfunc_t hash_sha2_512 = { 512/8, sizeof(SHA2_CONTEXT), diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 867afb087..0fdca6c67 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1461,7 +1461,7 @@ static const char *Mod_RemapBuggyTexture(const char *name, const qbyte *data, un { if (!strcmp(name, buggytextures[i].oldname)) { - unsigned int sum = Com_BlockChecksum(data, datalen); + unsigned int sum = CalcHashInt(&hash_md4, data, datalen); for (; i < sizeof(buggytextures)/sizeof(buggytextures[0]); i++) { if (strcmp(name, buggytextures[i].oldname)) @@ -5413,7 +5413,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi } if (i == LUMP_ENTITIES) continue; - chksum = Com_BlockChecksum(mod_base + header.lumps[i].fileofs, header.lumps[i].filelen); + chksum = CalcHashInt(&hash_md4, mod_base + header.lumps[i].fileofs, header.lumps[i].filelen); mod->checksum ^= chksum; if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES) diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 4d252881f..0ceb8aaee 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -8924,7 +8924,7 @@ void QCBUILTIN PF_sj_strhash (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl { //not quite the same, but oh well const char *str = PF_VarString(prinst, 0, pr_globals); int len = strlen(str); - G_FLOAT(OFS_RETURN) = Com_BlockChecksum(str, len); + G_FLOAT(OFS_RETURN) = CalcHashInt(&hash_md4, str, len); } #endif static void QCBUILTIN PF_StopSound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 46b558e71..bbeb5997f 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -1154,7 +1154,7 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, if (file) { char text[64]; - sv.csqcchecksum = Com_BlockChecksum(file, fsz); + sv.csqcchecksum = CalcHashInt(&hash_md4, file, fsz); sprintf(text, "0x%x", sv.csqcchecksum); InfoBuf_SetValueForStarKey(&svs.info, "*csprogs", text); sprintf(text, "0x%x", (unsigned int)fsz); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 52769cde9..0d8e7bc3d 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -266,19 +266,23 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade int raw = 0; char password[256] = ""; char userinfo[1024]; - enum { - //MUST BE ORDERED HIGHEST-PRIORITY-LAST - QTVAM_NONE, - QTVAM_PLAIN, -#ifdef TCPCONNECT -// QTVAM_CCITT, //16bit = ddos it - QTVAM_MD4, //fucked. required for eztv compat -// QTVAM_MD5, //fucked, no hash implemented - QTVAM_SHA1, //fucked too nowadays - QTVAM_SHA2_256, // - QTVAM_SHA2_512, // -#endif - } authmethod = QTVAM_NONE; + static struct + { + const char *name; //as seen in protocol + hashfunc_t *func; + int base; + } hashes[] = { + {"NONE", NULL, -1}, //for annonymous connections + {"PLAIN", NULL, 0}, +// {"CCITT", &hash_crc16, 16}, //'the CCITT standard CRC used by XMODEM'. 16bit anyway, don't allow, too easy to guess. +// {"MD4", &hash_md4, 15}, //md4 is available to all QW clients, but probably too weak to really use. +// {"MD5", &hash_md5, 16}, //blurgh + {"SHA1", &hash_sha1, 16}, + {"SHA2_256", &hash_sha2_256, 64}, + {"SHA2_512", &hash_sha2_512, 64}, +// {"SHA3_512", &hash_sha3_512, 16}, //eztv apparently allows this + }; + int authmethod = 0; //which of the above we're trying to use... start = headerstart; @@ -347,32 +351,20 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade { int thisauth; start = COM_ParseToken(start, NULL); - if (!strcmp(com_token, "NONE")) - thisauth = QTVAM_NONE; - else if (!strcmp(com_token, "PLAIN")) - thisauth = QTVAM_PLAIN; -#ifdef TCPCONNECT -// else if (!strcmp(com_token, "CCIT")) -// thisauth = QTVAM_CCITT; - else if (!strcmp(com_token, "MD4")) - thisauth = QTVAM_MD4; -// else if (!strcmp(com_token, "MD5")) -// thisauth = QTVAM_MD5; - else if (!strcmp(com_token, "SHA1")) - thisauth = QTVAM_SHA1; - else if (!strcmp(com_token, "SHA2_256")) - thisauth = QTVAM_SHA2_256; - else if (!strcmp(com_token, "SHA2_512")) - thisauth = QTVAM_SHA2_512; -#endif - else + for (thisauth = 1; ; thisauth++) { - thisauth = QTVAM_NONE; - Con_DPrintf("qtv: received unrecognised auth method (%s)\n", com_token); + if (thisauth == countof(hashes)) + { + Con_DPrintf("qtv: received unrecognised auth method (%s)\n", com_token); + break; + } + if (!strcmp(com_token, hashes[thisauth].name)) + { //we know this one. + if (authmethod < thisauth) + authmethod = thisauth; //and its better than the previous one we saw + break; + } } - - if (authmethod < thisauth) - authmethod = thisauth; } else if (!strcmp(com_token, "SOURCE")) { @@ -416,77 +408,38 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade p->hasauthed = true; //no password, no need to auth. else if (*password) { - hashfunc_t *func = NULL; - if (!*p->challenge && authmethod>QTVAM_PLAIN) + char hash[512]; + qbyte digest[DIGEST_MAXSIZE]; + if (!*p->challenge && hashes[authmethod].func) e = ("QTVSV 1\n" "PERROR: Challenge wasn't given...\n\n"); - else switch (authmethod) + switch(hashes[authmethod].base) { - case QTVAM_NONE: + default: + case -1: //no auth at all e = ("QTVSV 1\n" "PERROR: You need to provide a password.\n\n"); break; - case QTVAM_PLAIN: - p->hasauthed = !strcmp(qtv_password.string, password); + case 0: //plain text. challenge is not used. + Q_snprintfz(hash, sizeof(hash), "%s", qtv_password.string); break; -#ifdef TCPCONNECT - /*case QTVAM_CCITT: - { - unsigned short ushort_result; - QCRC_Init(&ushort_result); - QCRC_AddBlock(&ushort_result, p->challenge, strlen(p->challenge)); - QCRC_AddBlock(&ushort_result, qtv_password.string, strlen(qtv_password.string)); - p->hasauthed = (ushort_result == strtoul(password, NULL, 0)); - } - break;*/ - case QTVAM_MD4: - { - char hash[512]; - int md4sum[4]; - - Q_snprintfz(hash, sizeof(hash), "%s%s", p->challenge, qtv_password.string); - Com_BlockFullChecksum (hash, strlen(hash), (unsigned char*)md4sum); - Q_snprintfz(hash, sizeof(hash), "%X%X%X%X", md4sum[0], md4sum[1], md4sum[2], md4sum[3]); - p->hasauthed = !strcmp(password, hash); - } - break; -#ifdef HAVE_LEGACY //to be disabled at some point. - case QTVAM_SHA1: - { - char hash[512]; - int digest[5]; - - Q_snprintfz(hash, sizeof(hash), "%s%s", p->challenge, qtv_password.string); - CalcHash(&hash_sha1, (char*)digest, sizeof(digest), hash, strlen(hash)); - Q_snprintfz(hash, sizeof(hash), "%08X%08X%08X%08X%08X", digest[0], digest[1], digest[2], digest[3], digest[4]); - p->hasauthed = !strcmp(password, hash); - - if (!p->hasauthed) - func = &hash_sha1; - } - break; -#else - case QTVAM_SHA1: func = &hash_sha1; break; -#endif - case QTVAM_SHA2_256: func = &hash_sha256; break; - case QTVAM_SHA2_512: func = &hash_sha512; break; -// case QTVAM_MD5: func = &hash_md5; break; -#endif - default: - e = ("QTVSV 1\n" - "PERROR: server bug detected.\n\n"); - break; - } - if (func) - { - char hash[DIGEST_MAXSIZE*2+1]; - qbyte digest[DIGEST_MAXSIZE]; - + case 15: //fucked encoding(missing some leading 0s) Q_snprintfz(hash, sizeof(hash), "%s%s", p->challenge, qtv_password.string); - CalcHash(func, digest, sizeof(digest), hash, strlen(hash)); - Base64_EncodeBlock(digest, func->digestsize, hash, sizeof(hash)); - p->hasauthed = !strcmp(password, hash); + CalcHash(hashes[authmethod].func, digest, sizeof(digest), hash, strlen(hash)); + Q_snprintfz(hash, sizeof(hash), "%X%X%X%X", ((quint32_t*)digest)[0], ((quint32_t*)digest)[1], ((quint32_t*)digest)[2], ((quint32_t*)digest)[3]); + break; + case 16: + Q_snprintfz(hash, sizeof(hash), "%s%s", p->challenge, qtv_password.string); + CalcHash(hashes[authmethod].func, digest, sizeof(digest), hash, strlen(hash)); + Base16_EncodeBlock(digest, hashes[authmethod].func->digestsize, hash, sizeof(hash)); + break; + case 64: + Q_snprintfz(hash, sizeof(hash), "%s%s", p->challenge, qtv_password.string); + CalcHash(hashes[authmethod].func, digest, sizeof(digest), hash, strlen(hash)); + Base64_EncodeBlock(digest, hashes[authmethod].func->digestsize, hash, sizeof(hash)); + break; } + p->hasauthed = !strcmp(password, hash); if (!p->hasauthed && !e) { if (raw) @@ -499,66 +452,31 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade else { //no password, and not automagically authed - switch (authmethod) + switch (hashes[authmethod].base) { - case QTVAM_NONE: + case -1: if (raw) e = ""; else e = ("QTVSV 1\n" "PERROR: You need to provide a common auth method.\n\n"); break; - case QTVAM_PLAIN: + case 0: p->hasauthed = !strcmp(qtv_password.string, password); break; -#ifdef TCPCONNECT - /*case QTVAM_CCITT: - e = ("QTVSV 1\n" - "AUTH: CCITT\n" - "CHALLENGE: "); - goto hashedpassword;*/ - case QTVAM_MD4: - e = ("QTVSV 1\n" - "AUTH: MD4\n" - "CHALLENGE: "); - goto hashedpassword; - /*case QTVAM_MD5: - e = ("QTVSV 1\n" - "AUTH: MD5\n" - "CHALLENGE: "); - goto hashedpassword;*/ - case QTVAM_SHA1: - e = ("QTVSV 1\n" - "AUTH: SHA1\n" - "CHALLENGE: "); - goto hashedpassword; - case QTVAM_SHA2_256: - e = ("QTVSV 1\n" - "AUTH: SHA2_256\n" - "CHALLENGE: "); - goto hashedpassword; - case QTVAM_SHA2_512: - e = ("QTVSV 1\n" - "AUTH: SHA2_512\n" - "CHALLENGE: "); - goto hashedpassword; -hashedpassword: + default: { char tmp[32]; Sys_RandomBytes(tmp, sizeof(tmp)); tobase64(p->challenge, sizeof(p->challenge), tmp, sizeof(tmp)); } - VFS_WRITE(clientstream, e, strlen(e)); - VFS_WRITE(clientstream, p->challenge, strlen(p->challenge)); - e = "\n\n"; + e = va("QTVSV 1\n" + "AUTH: %s\n" + "CHALLENGE: %s\n\n", + hashes[authmethod].name, p->challenge); VFS_WRITE(clientstream, e, strlen(e)); return QTV_RETRY; -#endif - default: - e = ("QTVSV 1\n" - "PERROR: server bug detected.\n\n"); - break; } } diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 43f8763c8..85a9c6061 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -248,10 +248,10 @@ typedef struct void (*terminate) (unsigned char *digest, void *context); } hashfunc_t; extern hashfunc_t hash_sha1; -/*extern hashfunc_t hash_sha224; -extern hashfunc_t hash_sha256; -extern hashfunc_t hash_sha384; -extern hashfunc_t hash_sha512;*/ +/*extern hashfunc_t hash_sha2_224; +extern hashfunc_t hash_sha2_256; +extern hashfunc_t hash_sha2_384; +extern hashfunc_t hash_sha2_512;*/ #define HMAC HMAC_quake //stop conflicts... size_t CalcHash(hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen); size_t HMAC(hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datalen, const unsigned char *key, size_t keylen); diff --git a/fteqtv/source.c b/fteqtv/source.c index 23bf2d0db..37e4faedc 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -465,7 +465,7 @@ void Net_SendQTVConnectionRequest(sv_t *qtv, char *authmethod, char *challenge) snprintf(hash, sizeof(hash), "%s%s", challenge, qtv->connectpassword); Com_BlockFullChecksum (hash, strlen(hash), (unsigned char*)md4sum); - sprintf(hash, "%X%X%X%X", md4sum[0], md4sum[1], md4sum[2], md4sum[3]); + sprintf(hash, "%X%X%X%X", md4sum[0], md4sum[1], md4sum[2], md4sum[3]); //FIXME: bad formatting! str = hash; Net_QueueUpstream(qtv, strlen(str), str); str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str); diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index 8aa9f0068..6ad123701 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -1238,11 +1238,11 @@ static int sasl_scramsha1minus_initial(struct sasl_ctx_s *ctx, char *buf, int bu } static int sasl_scramsha256minus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize) { - return sasl_scram_initial(ctx, buf, bufsize, &hash_sha256, false); + return sasl_scram_initial(ctx, buf, bufsize, &hash_sha2_256, false); } static int sasl_scramsha512minus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize) { - return sasl_scram_initial(ctx, buf, bufsize, &hash_sha512, false); + return sasl_scram_initial(ctx, buf, bufsize, &hash_sha2_512, false); } static int sasl_scramsha1plus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize) { @@ -1250,11 +1250,11 @@ static int sasl_scramsha1plus_initial(struct sasl_ctx_s *ctx, char *buf, int buf } static int sasl_scramsha256plus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize) { - return sasl_scram_initial(ctx, buf, bufsize, &hash_sha256, true); + return sasl_scram_initial(ctx, buf, bufsize, &hash_sha2_256, true); } static int sasl_scramsha512plus_initial(struct sasl_ctx_s *ctx, char *buf, int bufsize) { - return sasl_scram_initial(ctx, buf, bufsize, &hash_sha512, true); + return sasl_scram_initial(ctx, buf, bufsize, &hash_sha2_512, true); } static void buf_cat(buf_t *buf, char *data, int len) diff --git a/plugins/plugin.h b/plugins/plugin.h index 6f46a4f9a..e824b244a 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -547,7 +547,7 @@ typedef struct //for plugins that need to read/write files... F(const char *,GetExtension,(const char *filename, const char *ignoreext)); F(void, FileBase, (const char *in, char *out, int outlen)); F(void, CleanUpPath, (char *str)); - F(unsigned int,BlockChecksum,(const void *buffer, int length)); //mostly for pack hashes. + F(unsigned int,BlockChecksum,(const void *buffer, size_t length)); //mostly for pack hashes. F(void*, LoadFile, (const char *fname, size_t *fsize)); //plugfuncs->Free //stuff that's useful for networking.