From 2ba06e7d83a3f5629038a47dd7e0be773ab4298d Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 23 Aug 2025 20:56:07 -0400 Subject: [PATCH] Switch to SHA256 for authentication SRB2Classic Port by Hanicef --- src/CMakeLists.txt | 2 +- src/Makefile | 1 - src/Makefile.d/features.mk | 6 +- src/Sourcefile | 1 + src/d_clisrv.c | 55 ++--- src/d_clisrv.h | 6 +- src/d_netcmd.c | 16 +- src/doomdef.h | 1 - src/lonesha256.c | 2 + src/lonesha256.h | 143 +++++++++++++ src/md5.c | 403 ------------------------------------- src/md5.h | 139 ------------- 12 files changed, 171 insertions(+), 604 deletions(-) create mode 100644 src/lonesha256.c create mode 100644 src/lonesha256.h delete mode 100644 src/md5.c delete mode 100644 src/md5.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b7b6aa774..d94b56560 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,7 +24,7 @@ set_property(TARGET SRB2SDL2 PROPERTY CXX_STANDARD 17) # Core sources target_sourcefile(c) -target_sources(SRB2SDL2 PRIVATE comptime.c md5.c config.h.in) +target_sources(SRB2SDL2 PRIVATE comptime.c config.h.in) ### Configuration set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL diff --git a/src/Makefile b/src/Makefile index dd309ba41..1dd50f2ca 100644 --- a/src/Makefile +++ b/src/Makefile @@ -62,7 +62,6 @@ # # Netplay incompatible # -------------------- -# NOMD5=1 - Disable MD5 checksum (validation tool). # NOPOSTPROCESSING=1 - ? # MOBJCONSISTANCY=1 - ?? # PACKETDROP=1 - ?? diff --git a/src/Makefile.d/features.mk b/src/Makefile.d/features.mk index 6b26ebe53..3326a39ff 100644 --- a/src/Makefile.d/features.mk +++ b/src/Makefile.d/features.mk @@ -3,7 +3,7 @@ # passthru_opts+=\ - NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ + NO_IPV6 NOHW NOPOSTPROCESSING\ MOBJCONSISTANCY PACKETDROP ZDEBUG\ HAVE_MINIUPNPC\ HAVE_DISCORDRPC DEVELOP @@ -20,10 +20,6 @@ opts+=-DHWRENDER sources+=$(call List,hardware/Sourcefile) endif -ifndef NOMD5 -sources+=md5.c -endif - ifndef NOZLIB ifndef NOPNG ifdef PNG_PKGCONFIG diff --git a/src/Sourcefile b/src/Sourcefile index 581140c50..e13a8a47f 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -137,3 +137,4 @@ k_mapuser.c k_stats.c h_timers.cpp stun.c +lonesha256.c diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1bbf83cc5..e42838e1b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -45,7 +45,7 @@ #include "lzf.h" #include "lua_script.h" #include "lua_hook.h" -#include "md5.h" +#include "lonesha256.h" #include "m_perfstats.h" // SRB2Kart @@ -146,7 +146,7 @@ boolean hu_stopped = false; char *reqpass; char **adminpass; UINT32 adminpasscount = 0; -char adminsalt[MAXPLAYERS][9]; +static char adminsalt[MAXNETNODES][9]; //I_StaticAssert(sizeof(netbuffer->u.salt) == sizeof(adminsalt[0])); // Client specific @@ -4286,23 +4286,22 @@ static void PT_Login(SINT8 node) if (client) return; -#ifndef NOMD5 + I_Assert((UINT8)node < sizeof(adminsalt) / sizeof(adminsalt[0])); + // I_GetRandomBytes should get it's data from a CSPRNG, so it's safe to use it here. I_GetRandomBytes(adminsalt[node], sizeof(adminsalt[node])); adminsalt[node][8] = '\0'; // convenience netbuffer->packettype = PT_LOGINCHALLENGE; memcpy(netbuffer->u.salt, adminsalt[node], sizeof(adminsalt[node])); HSendPacket(node, true, 0, sizeof(adminsalt[node])); -#else - (void)node; -#endif } static void PT_LoginChallenge(SINT8 node) { + char salt[9]; + //I_StaticAssert(sizeof(salt) == sizeof(netbuffer->u.salt)); doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); -#ifndef NOMD5 if (node != servernode) return; @@ -4312,27 +4311,24 @@ static void PT_LoginChallenge(SINT8 node) if (reqpass == NULL) return; // got PT_LOGINCHALLENGE but we didn't request a login - D_MD5PasswordPass((const UINT8 *)reqpass, strlen(reqpass), netbuffer->u.salt, &netbuffer->u.md5sum); + memcpy(salt, netbuffer->u.salt, sizeof(netbuffer->u.salt)); + D_SHA256PasswordPass((const UINT8 *)reqpass, strlen(reqpass), salt, netbuffer->u.sha256sum); Z_Free(reqpass); reqpass = NULL; netbuffer->packettype = PT_LOGINAUTH; - HSendPacket(servernode, true, 0, 16); -#else - (void)node; -#endif + HSendPacket(servernode, true, 0, sizeof(netbuffer->u.sha256sum)); } static void PT_LoginAuth(SINT8 node, INT32 netconsole) { doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); -#ifndef NOMD5 - UINT8 finalmd5[16];/* Well, it's the cool thing to do? */ + UINT8 finalsha256[32];/* Well, it's the cool thing to do? */ UINT32 i; if (client) return; - if (doomcom->datalength < 16)/* ignore partial sends */ + if (doomcom->datalength < sizeof(netbuffer->u.sha256sum))/* ignore partial sends */ return; if (adminsalt[node][0] == 0) @@ -4350,9 +4346,9 @@ static void PT_LoginAuth(SINT8 node, INT32 netconsole) for (i = 0; i < adminpasscount; i++) { // Do the final pass to compare with the sent md5 - D_MD5PasswordPass((const UINT8 *)adminpass[i], strlen(adminpass[i]), adminsalt[node], finalmd5); + D_SHA256PasswordPass((const UINT8 *)adminpass[i], strlen(adminpass[i]), adminsalt[node], finalsha256); - if (!memcmp(netbuffer->u.md5sum, finalmd5, 16)) + if (!memcmp(netbuffer->u.sha256sum, finalsha256, 32)) { adminsalt[node][0] = 0; CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]); @@ -4363,10 +4359,6 @@ static void PT_LoginAuth(SINT8 node, INT32 netconsole) adminsalt[node][0] = 0; CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]); -#else - (void)node; - (void)netconsole; -#endif } @@ -6303,29 +6295,18 @@ rewind_t *CL_RewindToTime(tic_t time) return rewindhead; } -void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest) +void D_SHA256PasswordPass(const UINT8 *buffer, size_t len, const char *salt, UINT8 dest[static 32]) { - // FIXME: replace with SHA-256, since MD5 is busted. -#ifdef NOMD5 - (void)buffer; - (void)len; - (void)salt; - memset(dest, 0, 16); -#else - char tmpbuf[256]; + UINT8 *tmpbuf; const size_t sl = strlen(salt); if (len > 256-sl) len = 256-sl; + tmpbuf = Z_Malloc(sizeof(char) * (sl + len), PU_STATIC, NULL); memcpy(tmpbuf, buffer, len); memmove(&tmpbuf[len], salt, sl); - //strcpy(&tmpbuf[len], salt); - len += strlen(salt); - if (len < 256) - memset(&tmpbuf[len],0,256-len); - // Yes, we intentionally md5 the ENTIRE buffer regardless of size... - md5_buffer(tmpbuf, 256, dest); -#endif + lonesha256(dest, tmpbuf, len+sl); + Z_Free(tmpbuf); } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 6335dbfdb..ae0e71a91 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -377,7 +377,7 @@ struct doomdata_t UINT8 filereceived; clientconfig_pak clientcfg; // 136 bytes char salt[9]; - UINT8 md5sum[16]; + UINT8 sha256sum[32]; serverinfo_pak serverinfo; // 1024 bytes serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) askinfo_pak askinfo; // 61 bytes @@ -587,7 +587,9 @@ ticcmd_t *D_LocalTiccmd(UINT8 ss); tic_t GetLag(INT32 node); UINT8 GetFreeXCmdSize(UINT8 playerid); -void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); +#ifndef __cplusplus +void D_SHA256PasswordPass(const UINT8 *buffer, size_t len, const char *salt, UINT8 dest[static 32]); +#endif extern UINT8 hu_redownloadinggamestate; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 4330bedff..c3f939e38 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4084,10 +4084,6 @@ void D_ClearPassword(void) // Remote Administration static void Command_Changepassword_f(void) { -#ifdef NOMD5 - // If we have no MD5 support then completely disable XD_LOGIN responses for security. - CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); -#else if (client) // cannot change remotely { CONS_Printf(M_GetText("Only the server can use this.\n")); @@ -4102,17 +4098,12 @@ static void Command_Changepassword_f(void) D_SetPassword(COM_Argv(1)); CONS_Printf(M_GetText("Password added.\n")); -#endif } // Remote Administration static void Command_Clearpassword_f(void) { -#ifdef NOMD5 - // If we have no MD5 support then completely disable XD_LOGIN responses for security. - CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); -#else if (client) // cannot change remotely { CONS_Printf(M_GetText("Only the server can use this.\n")); @@ -4121,16 +4112,12 @@ static void Command_Clearpassword_f(void) D_ClearPassword(); CONS_Printf(M_GetText("Passwords cleared.\n")); -#endif } static void Command_Login_f(void) { doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); -#ifdef NOMD5 - // If we have no MD5 support then completely disable XD_LOGIN responses for security. - CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); -#else + const char *pw; if (!netgame) @@ -4157,7 +4144,6 @@ static void Command_Login_f(void) netbuffer->packettype = PT_LOGIN; HSendPacket(servernode, true, 0, 0); -#endif } boolean IsPlayerAdmin(INT32 playernum) diff --git a/src/doomdef.h b/src/doomdef.h index 001d61bd3..765f69fcc 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -102,7 +102,6 @@ extern "C" { #endif // Special Hashing. -//#define NOMD5 //#define NOFILEHASH //#define NOVERIFYIWADS diff --git a/src/lonesha256.c b/src/lonesha256.c new file mode 100644 index 000000000..aac023e26 --- /dev/null +++ b/src/lonesha256.c @@ -0,0 +1,2 @@ +#define LONESHA256_IMPLEMENTATION +#include "lonesha256.h" diff --git a/src/lonesha256.h b/src/lonesha256.h new file mode 100644 index 000000000..2eea32672 --- /dev/null +++ b/src/lonesha256.h @@ -0,0 +1,143 @@ +/* +lonesha256.h - Portable, endian-proof, single-file, single-function sha256 implementation, originally based on LibTomCrypt + +To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring +rights to this software to the public domain worldwide. This software is distributed without any warranty. +You should have received a copy of the CC0 Public Domain Dedication along with this software. +If not, see . +*/ + +/* +lonesha256 supports the following three configurations: +#define LONESHA256_EXTERN + Default, should be used when using lonesha256 in multiple compilation units within the same project. +#define LONESHA256_IMPLEMENTATION + Must be defined in exactly one source file within a project for lonesha256 to be found by the linker. +#define LONESHA256_STATIC + Defines the lonesha256() function as static, useful if lonesha256 is only used in a single compilation unit. + +lonesha256 function: +(static|extern) int lonesha256 (unsigned char out[32], const unsigned char* in, size_t len) + writes the sha256 hash of the first "len" bytes in buffer "in" to buffer "out" + returns 0 on success, may return non-zero in future versions to indicate error +*/ + +//header section +#ifndef LONESHA256_H +#define LONESHA256_H + +//process configuration +#ifdef LONESHA256_STATIC + #define LONESHA256_IMPLEMENTATION + #define LSHA256DEF static +#else //LONESHA256_EXTERN + #define LSHA256DEF extern +#endif + +//includes +#include //size_t + +//lonesha256 declaration +LSHA256DEF int lonesha256(unsigned char[32], const unsigned char*, size_t); + +#endif //LONESHA256_H + +//implementation section +#ifdef LONESHA256_IMPLEMENTATION +#undef LONESHA256_IMPLEMENTATION + +//macros +#define S(x, n) (((((uint32_t)(x)&0xFFFFFFFFUL)>>(uint32_t)((n)&31))|((uint32_t)(x)<<(uint32_t)((32-((n)&31))&31)))&0xFFFFFFFFUL) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + (S(e, 6) ^ S(e, 11) ^ S(e, 25)) + (g ^ (e & (f ^ g))) + K[i] + W[i]; \ + t1 = (S(a, 2) ^ S(a, 13) ^ S(a, 22)) + (((a | b) & c) | (a & b)); \ + d += t0; \ + h = t0 + t1; +#define STORE32H(x, y) \ + (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); +#define LOAD32H(x, y) \ + x = ((uint32_t)((y)[0]&255)<<24)|((uint32_t)((y)[1]&255)<<16)|((uint32_t)((y)[2]&255)<<8)|((uint32_t)((y)[3]&255)); +#define STORE64H(x, y) \ + (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); +#define SHA256_COMPRESS(buff) \ + for (int i = 0; i < 8; i++) S[i] = sha256_state[i]; \ + for (int i = 0; i < 16; i++) LOAD32H(W[i], buff + (4*i)); \ + for (int i = 16; i < 64; i++) W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16]; \ + 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; \ + } \ + for (int i = 0; i < 8; i++) sha256_state[i] = sha256_state[i] + S[i]; + +//includes +#include //uint32_t, uint64_t +#include //memcpy + +//lonesha256 function +LSHA256DEF int lonesha256 (unsigned char out[32], const unsigned char* in, size_t len) { + //writes the sha256 hash of the first "len" bytes in buffer "in" to buffer "out" + //returns 0 on success, may return non-zero in future versions to indicate error + const uint32_t 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 + }; + uint64_t sha256_length = 0; + uint32_t sha256_state[8] = { + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL + }, S[8], W[64], t0, t1, t; + unsigned char sha256_buf[64]; + //process input in 64 byte chunks + while (len >= 64) { + SHA256_COMPRESS(in); + sha256_length += 64 * 8; + in += 64; + len -= 64; + } + //copy remaining bytes into sha256_buf + memcpy(sha256_buf, in, len); + //finish up (len now number of bytes in sha256_buf) + sha256_length += len * 8; + sha256_buf[len++] = 0x80; + //pad then compress if length is above 56 bytes + if (len > 56) { + while (len < 64) sha256_buf[len++] = 0; + SHA256_COMPRESS(sha256_buf); + len = 0; + } + //pad up to 56 bytes + while (len < 56) sha256_buf[len++] = 0; + //store length and compress + STORE64H(sha256_length, sha256_buf + 56); + SHA256_COMPRESS(sha256_buf); + //copy output + for (int i = 0; i < 8; i++) { + STORE32H(sha256_state[i], out + 4*i); + } + //return + return 0; +} + +#endif //LONESHA256_IMPLEMENTATION diff --git a/src/md5.c b/src/md5.c deleted file mode 100644 index d1c3a16b3..000000000 --- a/src/md5.c +++ /dev/null @@ -1,403 +0,0 @@ -// BLANKART -//----------------------------------------------------------------------------- -// Copyright (C) 1995-1996 by the Free Software Foundation, Inc. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file md5.c -/// \brief Functions to compute MD5 message digest of files or memory blocks -/// according to the definition of MD5 in RFC 1321 from April 1992. - -/* NOTE: The canonical source of this file is maintained with the GNU C - Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. */ -/* Written by Ulrich Drepper , 1995. */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#include -#include -#ifdef _MSC_VER -#pragma warning(disable : 4127) -#endif - -#if defined (STDC_HEADERS) || defined (_LIBC) - #include -#else - #ifndef HAVE_MEMCPY - #if !(defined (_WIN32) && !defined (__CYGWIN__)) && !defined (__APPLE__) - #define memcpy(d, s, n) bcopy ((s), (d), (n)) - #endif - #endif -#endif - -#include "md5.h" - -#include "endian.h" - -#if defined (SRB2_BIG_ENDIAN) - #define SWAP(n) \ - (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) -#else - #define SWAP(n) (n) -#endif - -/* This array contains the bytes used to pad the buffer to the next - 64-byte boundary. (RFC 1321, 3.1: Step 1) */ -static const unsigned char fillbuf[64] = { 0x80, 0 /*, 0, 0, ... */ }; - -/* Structure to save state of computation between the single steps. */ -struct md5_ctx -{ - md5_uint32 A; - md5_uint32 B; - md5_uint32 C; - md5_uint32 D; - - md5_uint32 total[2]; - md5_uint32 buflen; - char buffer[128]; -}; - -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ -static void md5_init_ctx (struct md5_ctx *ctx) -{ - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->total[0] = ctx->total[1] = 0; - ctx->buflen = 0; -} - -/* Put result from CTX in first 16 bytes following RESBUF. The result - must be in little endian byte order. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -static void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) -{ - ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); - ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); - ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); - ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); - - return resbuf; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -/* #define FF(b, c, d) ((b & c) | (~b & d)) */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - -/* Process LEN bytes of BUFFER, accumulating context into CTX. - It is assumed that LEN % 64 == 0. */ - -static void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) -{ - md5_uint32 correct_words[16]; - const md5_uint32 *words = buffer; - size_t nwords = len / sizeof (md5_uint32); - const md5_uint32 *endp = words + nwords; - md5_uint32 A = ctx->A; - md5_uint32 B = ctx->B; - md5_uint32 C = ctx->C; - md5_uint32 D = ctx->D; - - /* First increment the byte count. RFC 1321 specifies the possible - length of the file up to 2^64 bits. Here we only compute the - number of bytes. Do a double word increment. */ - ctx->total[0] = (md5_uint32)(len+ctx->total[0]); - if (ctx->total[0] < len) - ++ctx->total[1]; - - /* Process all bytes in the buffer with 64 bytes in each round of - the loop. */ - while (words < endp) - { - md5_uint32 *cwp = correct_words; - md5_uint32 A_save = A; - md5_uint32 B_save = B; - md5_uint32 C_save = C; - md5_uint32 D_save = D; - - /* First round: using the given function, the context and a constant - the next context is computed. Because the algorithms processing - unit is a 32-bit word and it is determined to work on words in - little endian byte order we perhaps have to change the byte order - before the computation. To reduce the work for the next steps - we store the swapped words in the array CORRECT_WORDS. */ - -#define OP(a, b, c, d, s, T) \ - do \ - { \ - a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ - ++words; \ - CYCLIC (a, s); \ - a += b; \ - } \ - while (0) - - /* It is unfortunate that C does not provide an operator for - cyclic rotation. Hope the C compiler is smart enough. */ -#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) - - /* Before we start, one word to the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i = 1..64 - */ - - /* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - - /* For the second to fourth round we have the possibly swapped words - in CORRECT_WORDS. Redefine the macro to take an additional first - argument specifying the function to use. */ -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do \ - { \ - a += f (b, c, d) + correct_words[k] + T; \ - CYCLIC (a, s); \ - a += b; \ - } \ - while (0) - - /* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - - /* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - - /* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - - /* Add the starting values of the context. */ - A += A_save; - B += B_save; - C += C_save; - D += D_save; - } - - /* Put checksum in context given as argument. */ - ctx->A = A; - ctx->B = B; - ctx->C = C; - ctx->D = D; -} - - -static void md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) -{ - /* When we already have some bits in our internal buffer concatenate - both inputs first. */ - if (ctx->buflen != 0) - { - size_t left_over = ctx->buflen; - size_t add = 128 - left_over > len ? len : 128 - left_over; - - memcpy (&ctx->buffer[left_over], buffer, add); - ctx->buflen = (md5_uint32)(add+ctx->buflen); - - if (left_over + add > 64) - { - md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); - /* The regions in the following copy operation cannot overlap. */ - memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], - (left_over + add) & 63); - ctx->buflen = (md5_uint32)((left_over + add) & 63); - } - - buffer = (const char *) buffer + add; - len -= add; - } - - /* Process available complete blocks. */ - if (len > 64) - { - md5_process_block (buffer, len & ~63, ctx); - buffer = (const char *) buffer + (len & ~63); - len &= 63; - } - - /* Move remaining bytes in internal buffer. */ - if (len > 0) - { - memcpy (ctx->buffer, buffer, len); - ctx->buflen = (md5_uint32)len; - } -} - - -/* Process the remaining bytes in the internal buffer and the usual - prolog according to the standard and write the result to RESBUF. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -static void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) -{ - /* Take yet unprocessed bytes into account. */ - md5_uint32 bytes = ctx->buflen; - size_t pad; - md5_uint32 *buffer = NULL; - - /* Now count remaining bytes. */ - ctx->total[0] += bytes; - if (ctx->total[0] < bytes) - ++ctx->total[1]; - - pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; - memcpy (&ctx->buffer[bytes], fillbuf, pad); - - /* Put the 64-bit file length in *bits* at the end of the buffer. */ - buffer = (void *)&ctx->buffer[bytes + pad]; - *buffer = SWAP (ctx->total[0] << 3); - buffer = (void *)&ctx->buffer[bytes + pad + 4]; - *buffer = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); - - /* Process last bytes. */ - md5_process_block (ctx->buffer, bytes + pad + 8, ctx); - - return md5_read_ctx (ctx, resbuf); -} - -/* Compute MD5 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 16 bytes - beginning at RESBLOCK. */ -int md5_stream (FILE *stream, void *resblock) -{ - /* Important: BLOCKSIZE must be a multiple of 64. */ -#define BLOCKSIZE 4096 - struct md5_ctx ctx; - char buffer[BLOCKSIZE + 72]; - size_t sum = 0; - - /* Initialize the computation context. */ - md5_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - do - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - } - while (sum < BLOCKSIZE && n != 0); - if (n == 0 && ferror (stream)) - return 1; - - /* If end of file is reached, end the loop. */ - if (n == 0) - break; - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - md5_process_block (buffer, BLOCKSIZE, &ctx); - } - - /* Add the last bytes if necessary. */ - if (sum > 0) - md5_process_bytes (buffer, sum, &ctx); - - /* Construct result in desired memory. */ - md5_finish_ctx (&ctx, resblock); - return 0; -} - -/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -void *md5_buffer (const char *buffer, size_t len, void *resblock) -{ - struct md5_ctx ctx; - - /* Initialize the computation context. */ - md5_init_ctx (&ctx); - - /* Process whole buffer but last len % 64 bytes. */ - md5_process_bytes (buffer, len, &ctx); - - /* Put result in desired memory area. */ - return md5_finish_ctx (&ctx, resblock); -} diff --git a/src/md5.h b/src/md5.h deleted file mode 100644 index 141422c22..000000000 --- a/src/md5.h +++ /dev/null @@ -1,139 +0,0 @@ -// BLANKART -//----------------------------------------------------------------------------- -// Copyright (C) 1995-1996 by the Free Software Foundation, Inc. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file md5.h -/// \brief Functions to compute MD5 message digest of files or memory blocks -/// according to the definition of MD5 in RFC 1321 from April 1992 - -/* NOTE: The canonical source of this file is maintained with the GNU C - Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. */ - -#ifndef _MD5_H -#define _MD5_H 1 - -#include - -#if defined (HAVE_LIMITS_H) || (defined (_LIBC) && _LIBC) || defined (_WIN32) -# include -#endif - -#define MD5_LEN 16 - -/* The following contortions are an attempt to use the C preprocessor - to determine an unsigned integral type that is 32 bits wide. An - alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but - doing that would require that the configure script compile and *run* - the resulting executable. Locally running cross-compiled executables - is usually not possible. */ - -#ifdef _LIBC -# include -typedef u_int32_t md5_uint32; -#else -# if defined __STDC__ && __STDC__ -# define UINT_MAX_32_BITS 4294967295U -# else -# define UINT_MAX_32_BITS 0xFFFFFFFF -# endif - -/* If UINT_MAX isn't defined, assume it's a 32-bit type. - This should be valid for all systems GNU cares about because - that doesn't include 16-bit systems, and only modern systems - (that certainly have ) have 64+-bit integral types. */ - -# ifndef UINT_MAX -# define UINT_MAX UINT_MAX_32_BITS -# endif - -# if UINT_MAX == UINT_MAX_32_BITS - typedef unsigned int md5_uint32; -# else -# if USHRT_MAX == UINT_MAX_32_BITS - typedef unsigned short md5_uint32; -# else -# if ULONG_MAX == UINT_MAX_32_BITS - typedef unsigned long md5_uint32; -# else - /* The following line is intended to evoke an error. - Using #error is not portable enough. */ - "Cannot determine unsigned 32-bit data type." -# endif -# endif -# endif -#endif - -#undef __P -#if defined (__STDC__) && __STDC__ -#define __P(x) x -#else -#define __P(x) () -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * The following three functions are build up the low level used in - * the functions `md5_stream' and `md5_buffer'. - */ -#if 0 -/* Initialize structure containing state of computation. - (RFC 1321, 3.3: Step 3) */ -extern void md5_init_ctx __P ((struct md5_ctx *ctx)); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is necessary that LEN is a multiple of 64!!! */ -extern void md5_process_block __P ((const void *buffer, size_t len, - struct md5_ctx *ctx)); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is NOT required that LEN is a multiple of 64. */ -extern void md5_process_bytes __P ((const void *buffer, size_t len, - struct md5_ctx *ctx)); - -/* Process the remaining bytes in the buffer and put result from CTX - in first 16 bytes following RESBUF. The result is always in little - endian byte order, so that a byte-wise output yields to the wanted - ASCII representation of the message digest. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); - - -/* Put result from CTX in first 16 bytes following RESBUF. The result is - always in little endian byte order, so that a byte-wise output yields - to the wanted ASCII representation of the message digest. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); - -#endif - -/* Compute MD5 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 16 bytes - beginning at RESBLOCK. */ -int md5_stream __P ((FILE *stream, void *resblock)); - -/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif