From 138663bf5a9c28052c689deeec8887a9ce2541af Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sat, 18 Mar 2023 05:18:04 -0700 Subject: [PATCH] Literally, unironically, draw the rest of the owl --- src/d_clisrv.c | 29 ++++++++++++++++++++++------- src/d_clisrv.h | 6 +++--- src/d_main.c | 26 +++++++++++++++----------- src/d_main.h | 2 +- src/d_netfil.c | 9 +++++---- src/d_player.h | 2 +- 6 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 48ef2d6bd..4ba2fdcea 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -47,6 +47,7 @@ #include "lua_hook.h" #include "md5.h" #include "m_perfstats.h" +#include "monocypher/monocypher.h" // SRB2Kart #include "k_kart.h" @@ -156,13 +157,13 @@ char connectedservername[MAXSERVERNAME]; /// \todo WORK! boolean acceptnewnode = true; -char lastReceivedKey[MAXNETNODES][32]; -char lastComputedChallenge[MAXNETNODES][32]; +uint8_t lastReceivedKey[MAXNETNODES][32]; +uint8_t lastSentChallenge[MAXNETNODES][32]; boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not tic_t firstconnectattempttime = 0; -char awaitingChallenge[32]; +uint8_t awaitingChallenge[32]; // engine @@ -833,7 +834,16 @@ static boolean CL_SendJoin(void) memcpy(&netbuffer->u.clientcfg.availabilities, R_GetSkinAvailabilities(false, false), MAXAVAILABILITY*sizeof(UINT8)); - memcpy(&netbuffer->u.clientcfg.challengeResponse, awaitingChallenge, 32); + uint8_t signature[64]; + crypto_eddsa_sign(signature, secret_key, awaitingChallenge, 32); + + if (crypto_eddsa_check(signature, public_key, awaitingChallenge, 32) != 0) + I_Error("Couldn't verify own key?"); + + // Testing + // memset(signature, 0, sizeof(signature)); + + memcpy(&netbuffer->u.clientcfg.challengeResponse, signature, sizeof(signature)); return HSendPacket(servernode, false, 0, sizeof (clientconfig_pak)); } @@ -4059,6 +4069,11 @@ static void HandleConnect(SINT8 node) if (playernode[i] != UINT8_MAX) // We use this to count players because it is affected by SV_AddWaitingPlayers when more than one client joins on the same tic, unlike playeringame and D_NumPlayers. UINT8_MAX denotes no node for that player connectedplayers++; + // Testing + // memset(netbuffer->u.clientcfg.challengeResponse, 0, sizeof(netbuffer->u.clientcfg.challengeResponse)); + + int sigcheck = crypto_eddsa_check(netbuffer->u.clientcfg.challengeResponse, lastReceivedKey[node], lastSentChallenge[node], 32); + if (bannednode && bannednode[node].banid != SIZE_MAX) { const char *reason = NULL; @@ -4140,9 +4155,9 @@ static void HandleConnect(SINT8 node) SV_SendRefuse(node, va(M_GetText("Too many people are connecting.\nPlease wait %d seconds and then\ntry rejoining."), (joindelay - 2 * cv_joindelay.value * TICRATE) / TICRATE)); } - else if (netgame && node != 0 && !memcmp(netbuffer->u.clientcfg.challengeResponse, lastComputedChallenge[node], 32)) + else if (netgame && node != 0 && sigcheck != 0) { - SV_SendRefuse(node, M_GetText("Failed to validate key exchange.")); + SV_SendRefuse(node, M_GetText("Signature verification failed.")); } else { @@ -4536,7 +4551,7 @@ static void HandlePacketFromAwayNode(SINT8 node) PT_ClientKey(node); break; case PT_SERVERCHALLENGE: - memset(awaitingChallenge, 0, 32); // TODO: ACTUALLY COMPUTE CHALLENGE RESPONSE IDIOT + memcpy(awaitingChallenge, netbuffer->u.serverchallenge.secret, sizeof(awaitingChallenge)); cl_mode = CL_ASKJOIN; break; default: diff --git a/src/d_clisrv.h b/src/d_clisrv.h index c400bb8a1..43e9bf540 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -256,7 +256,7 @@ struct clientconfig_pak UINT8 mode; char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME]; UINT8 availabilities[MAXAVAILABILITY]; - char challengeResponse[32]; + uint8_t challengeResponse[64]; } ATTRPACK; #define SV_SPEEDMASK 0x03 // used to send kartspeed @@ -460,8 +460,8 @@ extern UINT16 software_MAXPACKETLENGTH; extern boolean acceptnewnode; extern SINT8 servernode; extern char connectedservername[MAXSERVERNAME]; -extern char lastReceivedKey[MAXNETNODES][32]; -extern char lastComputedChallenge[MAXNETNODES][32]; +extern uint8_t lastReceivedKey[MAXNETNODES][32]; +extern uint8_t lastSentChallenge[MAXNETNODES][32]; void Command_Ping_f(void); extern tic_t connectiontimeout; diff --git a/src/d_main.c b/src/d_main.c index d1aacefd2..8bfe889cb 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -161,7 +161,7 @@ boolean dedicated = false; // For identity negotiation with netgame servers uint8_t public_key[32]; -uint8_t secret_key[32]; +uint8_t secret_key[64]; // // D_PostEvent @@ -1715,32 +1715,36 @@ void D_SRB2Main(void) ACS_Init(); CON_SetLoadingProgress(LOADED_ACSINIT); - // -- IT'S HOMEGROWN CRYPTO TIME -- - // TODO: This file should probably give a fuck about command line params, // or not be stored next to the EXE in a way that allows people to unknowingly send it to others. static char keyfile[16] = "rrid.dat"; - csprng(secret_key, 32); + static uint8_t seed[32]; + csprng(seed, 32); + crypto_eddsa_key_pair(secret_key, public_key, seed); + + int sk_size = sizeof(secret_key); + int pk_size = sizeof(public_key); + int totalsize = sk_size + pk_size; if (FIL_ReadFileOK(keyfile)) { UINT8 *readbuffer = NULL; UINT16 lengthRead = FIL_ReadFile(keyfile, &readbuffer); - if (readbuffer == NULL || lengthRead != 32) + if (readbuffer == NULL || lengthRead != totalsize) I_Error("Malformed keyfile"); - memcpy(secret_key, readbuffer, 32); + memcpy(secret_key, readbuffer, sk_size); + memcpy(public_key, readbuffer + sk_size, pk_size); } else { - if (!FIL_WriteFile(keyfile, secret_key, 32)) + uint8_t keybuffer[totalsize]; + memcpy(keybuffer, secret_key, sk_size); + memcpy(keybuffer + sk_size, public_key, pk_size); + if (!FIL_WriteFile(keyfile, keybuffer, totalsize)) I_Error("Couldn't open keyfile"); } - crypto_x25519_public_key(public_key, secret_key); - - // -- END HOMEGROWN CRYPTO TIME -- - //------------------------------------------------ COMMAND LINE PARAMS // this must be done after loading gamedata, diff --git a/src/d_main.h b/src/d_main.h index f6962e25c..199166c9e 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -32,7 +32,7 @@ extern char srb2path[256]; //Alam: SRB2's Home extern char addonsdir[MAX_WADPATH]; // Where addons are stored extern uint8_t public_key[32]; -extern uint8_t secret_key[32]; +extern uint8_t secret_key[64]; // the infinite loop of D_SRB2Loop() called from win_main for windows version void D_SRB2Loop(void) FUNCNORETURN; diff --git a/src/d_netfil.c b/src/d_netfil.c index cf57195cf..ee686f230 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1320,14 +1320,15 @@ void PT_ClientKey(INT32 node) // TODO // Stage 1: Exchange packets with no verification of their contents - // Stage 2: Exchange packets with a check, but no crypto (YOU ARE HERE) - // Stage 3: The crypto part + // Stage 2: Exchange packets with a check, but no crypto + // Stage 3: The crypto part (YOU ARE HERE) memcpy(lastReceivedKey[node], packet->key, 32); netbuffer->packettype = PT_SERVERCHALLENGE; - csprng(lastComputedChallenge[node], sizeof(serverchallenge_pak)); - memcpy(&netbuffer->u.serverchallenge, lastComputedChallenge[node], sizeof(serverchallenge_pak)); + + csprng(lastSentChallenge[node], sizeof(serverchallenge_pak)); + memcpy(&netbuffer->u.serverchallenge, lastSentChallenge[node], sizeof(serverchallenge_pak)); HSendPacket(node, false, 0, sizeof (serverchallenge_pak)); } diff --git a/src/d_player.h b/src/d_player.h index 8d09a5d2d..e7e3603cf 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -713,7 +713,7 @@ struct player_t mobj_t *stumbleIndicator; mobj_t *sliptideZipIndicator; - char public_key[32]; + uint8_t public_key[32]; #ifdef HWRENDER fixed_t fovadd; // adjust FOV for hw rendering