Merge pull request 'RRIDs' (#233) from rridport into next

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/233
This commit is contained in:
NepDisk 2026-03-31 16:00:11 +02:00
commit dd98ee93e2
28 changed files with 4409 additions and 74 deletions

View file

@ -1655,6 +1655,38 @@ freely, subject to the following restrictions:
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
--------------------------------------------------------------------------------
2-Clause BSD License
applies to:
- monocypher
Copyright (c) 2017-2020, Loup Vaillant
All rights reserved.
https://monocypher.org/
--------------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
MIT License
applies to:

View file

@ -276,6 +276,7 @@ add_subdirectory(sdl)
add_subdirectory(objects)
add_subdirectory(core)
add_subdirectory(acs)
add_subdirectory(monocypher)
# OS macros
if (UNIX)

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,7 @@
#include "d_net.h"
#include "d_netcmd.h"
#include "d_net.h"
#include "doomdef.h"
#include "tables.h"
#include "d_player.h"
#include "mserv.h"
@ -138,9 +139,23 @@ typedef enum
PT_SAY, // "Hey server, please send this chat message to everyone via XD_SAY"
PT_REQMAPQUEUE, // Client requesting a roundqueue operation
PT_CLIENTKEY, // "Here's my public key"
PT_SERVERCHALLENGE, // "Prove it"
PT_CHALLENGEALL, // Prove to the other clients you are who you say you are, sign this random bullshit!
PT_RESPONSEALL, // OK, here is my signature on that random bullshit
PT_RESULTSALL, // Here's what everyone responded to PT_CHALLENGEALL with, if this is wrong or you don't receive it disconnect
NUMPACKETTYPE
} packettype_t;
typedef enum
{
SIGN_OK,
SIGN_BADTIME, // Timestamp differs by too much, suspect reuse of an old challenge.
SIGN_BADIP // Asked to sign the wrong IP by an external host, suspect reuse of another server's challenge.
} shouldsign_t;
typedef struct consistancy_s
{
INT16 checksum; // Total consistancy checksum
@ -172,9 +187,7 @@ void SPrintConsistancy(char *out, consistancy_t *c);
void Command_Drop(void);
void Command_Droprate(void);
#endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
// Client to server packet
struct clientcmd_pak
@ -248,10 +261,6 @@ struct serverconfig_pak
UINT8 maxplayer;
boolean allownewplayer;
boolean discordinvites;
char server_name[MAXSERVERNAME];
char server_contact[MAXSERVERCONTACT];
char server_description[MAXSERVERDESCRIPTION];
} ATTRPACK;
struct filetx_pak
@ -291,6 +300,7 @@ struct clientconfig_pak
UINT8 mode;
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME];
UINT8 availabilities[MAXAVAILABILITY];
uint8_t challengeResponse[MAXSPLITSCREENPLAYERS][SIGNATURELENGTH];
} ATTRPACK;
#define SV_SPEEDMASK 0x03 // used to send kartspeed
@ -385,6 +395,32 @@ struct reqmapqueue_pak
UINT8 source;
} ATTRPACK;
struct clientkey_pak
{
uint8_t key[MAXSPLITSCREENPLAYERS][PUBKEYLENGTH];
} ATTRPACK;
struct serverchallenge_pak
{
uint8_t secret[CHALLENGELENGTH];
} ATTRPACK;
struct challengeall_pak
{
uint8_t secret[CHALLENGELENGTH];
} ATTRPACK;
struct responseall_pak
{
uint8_t signature[MAXSPLITSCREENPLAYERS][SIGNATURELENGTH];
} ATTRPACK;
struct resultsall_pak
{
// Maybe use a FAM in the future for space saving?
uint8_t signature[MAXPLAYERS][SIGNATURELENGTH];
} ATTRPACK;
struct netinfo_pak
{
UINT32 pingtable[MAXPLAYERS+1];
@ -410,33 +446,42 @@ struct doomdata_t
UINT8 ackreturn; // The return of the ack number
UINT8 packettype;
#ifdef SIGNGAMETRAFFIC
uint8_t signature[MAXSPLITSCREENPLAYERS][SIGNATURELENGTH];
#endif
UINT8 packetindex;
union
{
clientcmd_pak clientpak;
client2cmd_pak client2pak;
client3cmd_pak client3pak;
client4cmd_pak client4pak;
servertics_pak serverpak;
serverconfig_pak servercfg;
UINT8 textcmd[MAXTEXTCMD+1];
char filetxpak[sizeof (filetx_pak)];
char fileack[sizeof (fileack_pak)];
UINT8 filereceived;
clientconfig_pak clientcfg;
char salt[9];
UINT8 sha256sum[32];
serverinfo_pak serverinfo;
serverrefuse_pak serverrefuse;
serverinfoupdate_pak serverinfoupdate;
askinfo_pak askinfo;
msaskinfo_pak msaskinfo;
plrinfo playerinfo[MAXPLAYERINFO];
INT32 filesneedednum;
filesneededconfig_pak filesneededcfg;
netinfo_pak netinfo;
say_pak say;
reqmapqueue_pak reqmapqueue; // Formerly XD_REQMAPQUEUE
// NOTICE: UPDATE THE COMMENT SIZES WHEN YOU CHANGE STUFF.
clientcmd_pak clientpak; // 96 bytes
client2cmd_pak client2pak; // 110 bytes
client3cmd_pak client3pak; // 124 bytes
client4cmd_pak client4pak; // 138 bytes
servertics_pak serverpak; // 633 bytes
serverconfig_pak servercfg; // 33 bytes
UINT8 textcmd[MAXTEXTCMD+1]; // 257 bytes
char filetxpak[sizeof (filetx_pak)]; // 12 bytes
char fileack[sizeof (fileack_pak)]; // 3 bytes
UINT8 filereceived; // 1 byte
clientconfig_pak clientcfg; // 378 bytes
char salt[9]; // 9 bytes
UINT8 sha256sum[32]; // 32 bytes
serverinfo_pak serverinfo; // 1311 bytes
serverrefuse_pak serverrefuse; // 255 bytes
serverinfoupdate_pak serverinfoupdate; // 1406 bytes
askinfo_pak askinfo; // 5 bytes
msaskinfo_pak msaskinfo; // 26 bytes
plrinfo playerinfo[MAXPLAYERINFO]; // 1056 bytes
INT32 filesneedednum; // 4 bytes
filesneededconfig_pak filesneededcfg; // 921 bytes
netinfo_pak netinfo; // 396 bytes
say_pak say; // 227 bytes
reqmapqueue_pak reqmapqueue; // 6 bytes. Formerly XD_REQMAPQUEUE
clientkey_pak clientkey; // 32 bytes
serverchallenge_pak serverchallenge; // 256 bytes
challengeall_pak challengeall; // 256 bytes
responseall_pak responseall; // 256 bytes
resultsall_pak resultsall; // 1024 bytes (2048 bytes in 32P)
} u; // This is needed to pack diff packet types data together
} ATTRPACK;
@ -478,6 +523,7 @@ extern consvar_t cv_serverinfoscreen;
#define KICK_MSG_GRIEF 7
#define KICK_MSG_CUSTOM_KICK 8
#define KICK_MSG_CUSTOM_BAN 9
#define KICK_MSG_SIGFAIL 10
typedef enum
{
@ -505,9 +551,18 @@ extern char connectedservername[MAXSERVERNAME];
extern char connectedservercontact[MAXSERVERCONTACT];
extern char connectedserverdescription[MAXSERVERDESCRIPTION];
extern UINT32 ourIP;
extern uint8_t lastReceivedKey[MAXNETNODES][MAXSPLITSCREENPLAYERS][PUBKEYLENGTH];
extern uint8_t lastSentChallenge[MAXNETNODES][CHALLENGELENGTH];
extern uint8_t lastChallengeAll[CHALLENGELENGTH];
extern uint8_t lastReceivedSignature[MAXPLAYERS][SIGNATURELENGTH];
extern uint8_t knownWhenChallenged[MAXPLAYERS][PUBKEYLENGTH];
extern boolean expectChallenge;
void Command_Ping_f(void);
extern tic_t connectiontimeout;
extern tic_t jointimeout;
extern tic_t freezetimeout[MAXNETNODES];
extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS];
@ -528,10 +583,25 @@ extern consvar_t cv_joinnextround;
extern consvar_t cv_discordinvites;
#ifdef DEVELOP
extern consvar_t cv_badjoin;
extern consvar_t cv_badtraffic;
extern consvar_t cv_badresponse;
extern consvar_t cv_noresponse;
extern consvar_t cv_nochallenge;
extern consvar_t cv_badresults;
extern consvar_t cv_noresults;
extern consvar_t cv_badtime;
extern consvar_t cv_badip;
#endif
// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low, tic_t basetic);
void D_ClientServerInit(void);
void GenerateChallenge(uint8_t *buf);
shouldsign_t ShouldSignChallenge(uint8_t *message);
// Initialise the other field
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
void SendNetXCmdForPlayer(UINT8 playerid, netxcmd_t id, const void *param, size_t nparam);
@ -558,6 +628,8 @@ typedef enum
CL_PREPAREHTTPFILES,
CL_DOWNLOADHTTPFILES,
#endif
CL_SENDKEY,
CL_WAITCHALLENGE,
} cl_mode_t;
// Create any new ticcmds and broadcast to other players.
@ -673,10 +745,21 @@ void CL_ClearRewinds(void);
rewind_t *CL_SaveRewindPoint(size_t demopos);
rewind_t *CL_RewindToTime(tic_t time);
void HandleSigfail(const char *string);
void DoSayPacket(SINT8 target, UINT8 flags, UINT8 source, char *message);
void DoSayPacketFromCommand(SINT8 target, size_t usedargs, UINT8 flags);
void SendServerNotice(SINT8 target, char *message);
// We give clients a chance to verify each other once per race.
// When is that challenge sent, and when should clients bail if they don't receive the responses?
#define CHALLENGEALL_START (TICRATE*10)
#define CHALLENGEALL_KICKUNRESPONSIVE (TICRATE*12)
#define CHALLENGEALL_SENDRESULTS (TICRATE*14)
#define CHALLENGEALL_CLIENTCUTOFF (TICRATE*16)
extern uint8_t awaitingChallenge[CHALLENGELENGTH]; // The message the server asked our client to sign when joining;
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -74,6 +74,9 @@
#include "m_perfstats.h"
#include "core/memory.h"
#include "monocypher/monocypher.h"
#include "stun.h"
// SRB2Kart
#include "k_grandprix.h"
#include "k_boss.h"
@ -89,6 +92,10 @@
#include <tracy/tracy/Tracy.hpp>
#ifdef HAVE_SDL
#include <SDL3/SDL_filesystem.h>
#endif
// Put hashes here to get them out of header hell.
#define ASSET_HASH_SRB2_SRB 0xf3ec1ea4d0eca4a9
#define ASSET_HASH_GFX_KART 0xc91b0d43f5ba131f
@ -179,6 +186,10 @@ INT32 eventhead, eventtail;
boolean dedicated = false;
// For identity negotiation with netgame servers
uint8_t g_public_key[MAXSPLITSCREENPLAYERS][PUBKEYLENGTH];
uint8_t g_secret_key[MAXSPLITSCREENPLAYERS][PRIVKEYLENGTH];
boolean loaded_config = false;
//
@ -1868,6 +1879,57 @@ void D_SRB2Main(void)
ACS_Init();
CON_SetLoadingProgress(LOADED_ACSINIT);
// Read / create RRID key files in srb2home/private_keys
// About as obvious as I can make this say DONT SHARE.
#define RRIDWARNINGNAME "DO_NOT_SHARE_THESE"
#define RRIDWARNINGMESSAGE "This folder contains keys that should not be shared.\nThe base game and mods may use these to keep track of gamedata."
static char keyfile[MAXSPLITSCREENPLAYERS][10] = {"bkid1.dat", "bkid2.dat", "bkid3.dat", "bkid4.dat"};
INT32 snum;
for (snum = 0; snum < MAXSPLITSCREENPLAYERS; snum++)
{
char base_path[MAX_WADPATH];
char file[MAX_WADPATH];
strcpy(base_path, srb2home);
strcat(base_path, PATHSEP "private_keys" PATHSEP);
M_MkdirEach(base_path, M_PathParts(base_path) - 2, 0755);
strcpy(file, base_path);
strcat(file, keyfile[snum]);
static uint8_t seed[32];
csprng(seed, 32);
crypto_eddsa_key_pair(g_secret_key[snum], g_public_key[snum], seed);
int sk_size = sizeof(g_secret_key[snum]);
int pk_size = sizeof(g_public_key[snum]);
int totalsize = sk_size + pk_size;
if (FIL_ReadFileOK(file))
{
UINT8 *readbuffer = NULL;
UINT16 lengthRead = FIL_ReadFile(file, &readbuffer);
if (readbuffer == NULL || lengthRead != totalsize)
I_Error("Malformed keyfile %d", snum);
memcpy(g_secret_key[snum], readbuffer, sk_size);
memcpy(g_public_key[snum], readbuffer + sk_size, pk_size);
}
else
{
uint8_t *keybuffer = (uint8_t *)malloc(totalsize);
memcpy(keybuffer, g_secret_key[snum], sk_size);
memcpy(keybuffer + sk_size, g_public_key[snum], pk_size);
if (!FIL_WriteFile(file, keybuffer, totalsize))
I_Error("Couldn't open key file %d", snum);
if (!FIL_WriteFile(va("%s%s",base_path , RRIDWARNINGNAME), RRIDWARNINGMESSAGE, strlen(RRIDWARNINGMESSAGE)))
I_Error("Failed to create BKID warning file.");
free(keybuffer);
}
}
#undef RRIDWARNINGNAME
#undef RRIDWARNINGMESSAGE
//------------------------------------------------ COMMAND LINE PARAMS
// this must be done after loading gamedata,

View file

@ -64,6 +64,9 @@ extern char srb2path[256]; //Alam: SRB2's Home
const char *D_GetFancyBranchName(void);
extern uint8_t g_public_key[MAXSPLITSCREENPLAYERS][PUBKEYLENGTH];
extern uint8_t g_secret_key[MAXSPLITSCREENPLAYERS][PRIVKEYLENGTH];
// the infinite loop of D_SRB2Loop() called from win_main for windows version
void D_SRB2Loop(void) FUNCNORETURN;

View file

@ -31,6 +31,7 @@
#include "d_main.h" // srb2home
#include "stun.h"
#include "byteptr.h"
#include "monocypher/monocypher.h"
#include "qs22j.h"
@ -81,6 +82,7 @@ boolean (*I_NetOpenSocket)(void) = NULL;
boolean (*I_Ban) (INT32 node) = NULL;
void (*I_ClearBans)(void) = NULL;
const char *(*I_GetNodeAddress) (INT32 node) = NULL;
UINT32 (*I_GetNodeAddressInt) (INT32 node) = NULL;
const char *(*I_GetBanAddress) (size_t ban) = NULL;
const char *(*I_GetBanMask) (size_t ban) = NULL;
const char *(*I_GetBanUsername) (size_t ban) = NULL;
@ -90,6 +92,7 @@ boolean (*I_SetBanAddress) (const char *address, const char *mask) = NULL;
boolean (*I_SetBanUsername) (const char *username) = NULL;
boolean (*I_SetBanReason) (const char *reason) = NULL;
boolean (*I_SetUnbanTime) (time_t timestamp) = NULL;
boolean (*I_IsExternalAddress) (const void *p) = NULL;
bannednode_t *bannednode = NULL;
@ -470,7 +473,12 @@ static void InitAck(void)
ackpak[i].acknum = 0;
for (i = 0; i < MAXNETNODES; i++)
{
InitNode(&nodes[i]);
csprng(lastSentChallenge[i], sizeof(lastSentChallenge[i]));
csprng(lastReceivedKey[i], sizeof(lastReceivedKey[i]));
}
}
/** Removes all acks of a given packet type
@ -547,6 +555,9 @@ void Net_CloseConnection(INT32 node)
if (server)
SV_AbortLuaFileTransfer(node);
I_NetFreeNodenum(node);
csprng(lastSentChallenge[node], sizeof(lastSentChallenge[node]));
csprng(lastReceivedKey[node], sizeof(lastReceivedKey[node]));
}
//
@ -647,12 +658,31 @@ static const char *packettypename[NUMPACKETTYPE] =
"TEXTCMD2",
"TEXTCMD3",
"TEXTCMD4",
"TELLFILESNEEDED",
"MOREFILESNEEDED",
"CLIENTJOIN",
"NODETIMEOUT",
"LOGIN",
"LOGINCHALLENGE",
"LOGINAUTH",
"PING"
"PING",
"SERVERINFOUPDATE",
"SAY",
"REQMAPQUEUE",
"CLIENTKEY",
"SERVERCHALLENGE",
"CHALLENGEALL",
"RESPONSEALL",
"RESULTSALL"
};
static void DebugPrintpacket(const char *header)
@ -835,6 +865,34 @@ static boolean ShouldDropPacket(void)
}
#endif
// Unused because Eidolon correctly pointed out that +512b on every packet was scary.
#ifdef SIGNGAMETRAFFIC
boolean IsPacketSigned(int packettype)
{
switch (packettype)
{
case PT_CLIENTCMD:
case PT_CLIENT2CMD:
case PT_CLIENT3CMD:
case PT_CLIENT4CMD:
case PT_CLIENTMIS:
case PT_CLIENT2MIS:
case PT_CLIENT3MIS:
case PT_CLIENT4MIS:
case PT_TEXTCMD:
case PT_TEXTCMD2:
case PT_TEXTCMD3:
case PT_TEXTCMD4:
case PT_LOGIN:
case PT_ASKLUAFILE:
case PT_SENDINGLUAFILE:
return true;
default:
return false;
}
}
#endif
//
// HSendPacket
//
@ -842,6 +900,36 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
{
doomdata_t *netbuffer = DOOMCOM_DATA(doomcom);
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
#ifdef SIGNGAMETRAFFIC
if (IsPacketSigned(netbuffer->packettype))
{
int i;
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
const void* message = &netbuffer->u;
//CONS_Printf("Signing packet type %d of length %d\n", netbuffer->packettype, packetlength);
crypto_eddsa_sign(netbuffer->signature[i], g_secret_key[i], message, packetlength);
}
#ifdef DEVELOP
if (cv_badtraffic.value)
{
CV_AddValue(&cv_badtraffic, -1);
CONS_Alert(CONS_WARNING, "cv_badtraffic enabled, scrubbing signature from HSendPacket\n");
memset(netbuffer->signature, 0, sizeof(netbuffer->signature));
}
#endif
}
else
{
//CONS_Printf("NOT signing PT_%d of length %d, it doesn't need to be\n", netbuffer->packettype, packetlength);
memset(netbuffer->signature, 0, sizeof(netbuffer->signature));
}
#endif
if (node == 0) // Packet is to go back to us
{
if ((rebound_head+1) % MAXREBOUND == rebound_tail)

View file

@ -51,6 +51,7 @@ extern SINT8 nodetoplayer3[MAXNETNODES]; // Say the numplayer for this node if a
extern SINT8 nodetoplayer4[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen == 3)
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
extern boolean nodeneedsauth[MAXNETNODES];
extern boolean serverrunning;
@ -72,6 +73,8 @@ void Net_AbortPacketType(UINT8 packettype);
void Net_SendAcks(INT32 node);
void Net_WaitAllAckReceived(UINT32 timeout);
boolean IsPacketSigned(int packettype);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -792,6 +792,9 @@ consvar_t cv_nettimeout = CVAR_INIT ("nettimeout", "210", CV_CALL|CV_SAVE, netti
consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "210", CV_CALL|CV_SAVE, nettimeout_cons_t, JoinTimeout_OnChange);
consvar_t cv_maxping = CVAR_INIT ("maxdelay", "20", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_validate_pubkey= CVAR_INIT ("prevent_duplicate_pubkey", "On", 0, CV_OnOff, NULL); // Validate for duplicate players on Join.
static CV_PossibleValue_t lagless_cons_t[] = {{-1, "Worst"}, {0, "Best"}, {1, "Lagless"}, {0, NULL}};
consvar_t cv_lagless = CVAR_INIT ("lagless", "Lagless", CV_SAVE|CV_NETVAR|CV_CALL, lagless_cons_t, Lagless_OnChange);
@ -1147,6 +1150,7 @@ void D_RegisterServerCommands(void)
COM_AddCommand("ping", Command_Ping_f);
CV_RegisterVar(&cv_nettimeout);
CV_RegisterVar(&cv_jointimeout);
CV_RegisterVar(&cv_validate_pubkey);
CV_RegisterVar(&cv_kicktime);
CV_RegisterVar(&cv_skipmapcheck);
CV_RegisterVar(&cv_sleep);
@ -1348,6 +1352,18 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_netticbuffer);
CV_RegisterVar(&cv_mindelay);
#ifdef DEVELOP
CV_RegisterVar(&cv_badjoin);
CV_RegisterVar(&cv_badtraffic);
CV_RegisterVar(&cv_badresponse);
CV_RegisterVar(&cv_noresponse);
CV_RegisterVar(&cv_nochallenge);
CV_RegisterVar(&cv_badresults);
CV_RegisterVar(&cv_noresults);
CV_RegisterVar(&cv_badtime);
CV_RegisterVar(&cv_badip);
#endif
// HUD
CV_RegisterVar(&cv_itemfinder);

View file

@ -52,6 +52,8 @@
#include "m_misc.h"
#include "m_menu.h"
#include "filesrch.h"
#include "stun.h"
#include <errno.h>
@ -1339,6 +1341,45 @@ void PT_FileReceived(SINT8 node)
SV_EndFileSend(doomcom->remotenode);
}
// Someone knocked on the door with their public key.
// Give them a challenge to sign in their PT_CLIENTJOIN.
void PT_ClientKey(INT32 node)
{
if (!server)
return;
doomdata_t *netbuffer = DOOMCOM_DATA(doomcom);
clientkey_pak *packet = (void*)&netbuffer->u.clientkey;
memcpy(lastReceivedKey[node], packet->key, sizeof(lastReceivedKey[node]));
netbuffer->packettype = PT_SERVERCHALLENGE;
GenerateChallenge(lastSentChallenge[node]);
memcpy(&netbuffer->u.serverchallenge, lastSentChallenge[node], sizeof(serverchallenge_pak));
HSendPacket(node, true, 0, sizeof (serverchallenge_pak));
// Client's not in the server yet, but we still need to lock up the node.
// Otherwise, someone else could request a challenge on the same node and trash it.
nodeneedsauth[node] = true;
freezetimeout[node] = I_GetTime() + jointimeout;
}
void PT_ServerChallenge(INT32 node, cl_mode_t *cl_mode)
{
if (server && serverrunning && node != servernode)
{
Net_CloseConnection(node);
return;
}
if (*cl_mode != CL_WAITCHALLENGE)
return;
doomdata_t *netbuffer = DOOMCOM_DATA(doomcom);
memcpy(awaitingChallenge, netbuffer->u.serverchallenge.secret, sizeof(awaitingChallenge));
*cl_mode = CL_ASKJOIN;
}
static void SendAckPacket(fileack_pak *packet, UINT8 fileid)
{
size_t packetsize;

View file

@ -116,6 +116,10 @@ boolean CL_CheckDownloadable(void);
boolean CL_SendFileRequest(void);
void PT_RequestFile(INT32 node);
void PT_ClientKey(INT32 node);
void PT_ServerChallenge(INT32 node, cl_mode_t *cl_mode);
typedef enum
{
LFTNS_NONE, // This node is not connected

View file

@ -891,6 +891,8 @@ struct player_t
boolean walltransfered;
UINT8 walltransferboost;
uint8_t public_key[PUBKEYLENGTH];
#ifdef HWRENDER
fixed_t fovadd; // adjust FOV for hw rendering
#endif

View file

@ -528,6 +528,12 @@ extern int compuncommitted;
#define MAX_VOLUME 100
// Crypto/RRID primitives
#define PUBKEYLENGTH 32 // Enforced by Monocypher EdDSA
#define PRIVKEYLENGTH 64 // Enforced by Monocypher EdDSA
#define SIGNATURELENGTH 64 // Enforced by Monocypher EdDSA
#define CHALLENGELENGTH 64 // Servers verify client identity by giving them messages to sign. How long are these messages?
#ifdef HAVE_CURL
#define MASTERSERVER
#else

View file

@ -778,6 +778,7 @@ extern consvar_t cv_forceskin; // force clients to use the server's skin
extern consvar_t cv_downloading; // allow clients to downloading WADs.
extern consvar_t cv_nettimeout; // SRB2Kart: Advanced server options menu
extern consvar_t cv_jointimeout;
extern consvar_t cv_validate_pubkey;
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
extern INT32 serverplayer;
extern INT32 adminplayers[MAXPLAYERS];

View file

@ -925,13 +925,14 @@ const char *blancredits[] = {
"\"hayaunderscore\" aka \"DeltaKanyx\"",
"\"Guilmon35249vr\"",
"Vivian \"toaster\" Grannell", // Horncode
"AJ \"Tyron\" Martinez", // Horncode, PT_SAY
"AJ \"Tyron\" Martinez", // Horncode, PT_SAY, RRID
"\"Superstarxalien\"", // Horncode
"\"Freaky Mutant Man\"", // Color profiles menu
"\"blondedradio\"", // Screen-tracking item roulette, lifted near-directly from RadioRacers
"\"Antoine De Grandpré\"", // Zero Deadzone fix
"\"Skirlez\"", // PT_SAY packet fixes
"Sally \"TehRealSalt\" Cochenour", // Map Buffer rewrite, Voting rewrites
"\"Jartha\"", // Various bugfixes, RRID
"",
"\1Item Design",
"\"NepDisk\"",

View file

@ -71,6 +71,7 @@
#include "f_dscredits.hpp"
#include "strbuf.h"
#include "k_vote.h"
#include "d_clisrv.h"
#ifdef HAVE_DISCORDRPC
#include "discord.h"
@ -3174,6 +3175,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
SINT8 xtralife;
uint8_t public_key[PUBKEYLENGTH];
// SRB2kart
INT32 itemtype;
INT32 itemamount;
@ -3255,6 +3258,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE|PF_FLIPCAM));
memcpy(&public_key, &players[player].public_key, sizeof(public_key));
// SRB2kart
if (betweenmaps || leveltime <= starttime || spectator == true)
{
@ -3531,6 +3536,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
K_BotReborn(p);
memcpy(&p->public_key, &public_key, sizeof(p->public_key));
if (follower)
P_RemoveMobj(follower);

View file

@ -22,7 +22,7 @@
/// \def MAXPACKETLENGTH
/// For use in a LAN
#define MAXPACKETLENGTH 2048
#define MAXPACKETLENGTH 2063
/// \def INETPACKETLENGTH
/// For use on the internet
#define INETPACKETLENGTH 1450
@ -157,6 +157,7 @@ extern void (*I_NetRegisterHolePunch)(void);
extern boolean (*I_Ban) (INT32 node);
extern void (*I_ClearBans)(void);
extern const char *(*I_GetNodeAddress) (INT32 node);
extern UINT32 (*I_GetNodeAddressInt) (INT32 node);
extern const char *(*I_GetBanAddress) (size_t ban);
extern const char *(*I_GetBanMask) (size_t ban);
extern const char *(*I_GetBanUsername) (size_t ban);
@ -166,6 +167,7 @@ extern boolean (*I_SetBanAddress) (const char *address,const char *mask);
extern boolean (*I_SetBanUsername) (const char *username);
extern boolean (*I_SetBanReason) (const char *reason);
extern boolean (*I_SetUnbanTime) (time_t timestamp);
extern boolean (*I_IsExternalAddress) (const void *p);
struct bannednode_t
{

View file

@ -457,6 +457,20 @@ static const char *SOCK_GetNodeAddress(INT32 node)
return SOCK_AddrToStr(&clientaddress[node]);
}
static UINT32 SOCK_GetNodeAddressInt(INT32 node)
{
if (nodeconnected[node] && clientaddress[node].any.sa_family == AF_INET)
{
return clientaddress[node].ip4.sin_addr.s_addr;
}
else
{
I_Error("SOCK_GetNodeAddressInt: Node %d is not IPv4!\n", node);
}
return 0;
}
static const char *SOCK_GetBanAddress(size_t ban)
{
if (ban >= numbans)
@ -549,7 +563,7 @@ static void cleanupnodes(void)
// Why can't I start at zero?
for (j = 1; j < MAXNETNODES; j++)
if (!(nodeingame[j] || SendingFile(j)))
if (!(nodeingame[j] || nodeneedsauth[j] || SendingFile(j)))
nodeconnected[j] = false;
}
@ -579,7 +593,6 @@ static SINT8 getfreenode(void)
return -1;
}
#ifdef _DEBUG
void Command_Numnodes(void)
{
INT32 connected = 0;
@ -617,7 +630,6 @@ void Command_Numnodes(void)
"Ingame: %d\n",
connected, ingame);
}
#endif
static boolean hole_punch(ssize_t c)
{
@ -1691,6 +1703,30 @@ static void SOCK_ClearBans(void)
banned = NULL;
}
// https://github.com/jameds/holepunch/blob/master/holepunch.c#L75
static int SOCK_IsExternalAddress (const void *p)
{
const int a = ((const unsigned char*)p)[0];
const int b = ((const unsigned char*)p)[1];
if (*(const UINT32*)p == (UINT32)~0)/* 255.255.255.255 */
return 0;
switch (a)
{
case 0:
case 10:
case 127:
return 0;
case 172:
return (b & ~15) != 16;/* 16 - 31 */
case 192:
return b != 168;
default:
return 1;
}
}
boolean I_InitTcpNetwork(void)
{
char serverhostname[255];
@ -1782,6 +1818,7 @@ boolean I_InitTcpNetwork(void)
I_Ban = SOCK_Ban;
I_ClearBans = SOCK_ClearBans;
I_GetNodeAddress = SOCK_GetNodeAddress;
I_GetNodeAddressInt = SOCK_GetNodeAddressInt;
I_GetBanAddress = SOCK_GetBanAddress;
I_GetBanMask = SOCK_GetBanMask;
I_GetBanUsername = SOCK_GetBanUsername;
@ -1791,6 +1828,7 @@ boolean I_InitTcpNetwork(void)
I_SetBanUsername = SOCK_SetBanUsername;
I_SetBanReason = SOCK_SetBanReason;
I_SetUnbanTime = SOCK_SetUnbanTime;
I_IsExternalAddress = SOCK_IsExternalAddress;
bannednode = SOCK_bannednode;
return ret;

View file

@ -23,6 +23,7 @@
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#include "lua_hook.h" // hook_cmd_running errors
#include "m_misc.h" // GetPrettyRRID
static int lib_iteratePlayers(lua_State *L)
{
@ -465,7 +466,8 @@ static int lib_lenLocalplayers(lua_State *L)
X(recoverydashcharge) \
X(recoverydash) \
X(tripwireunstuck) \
X(bumpunstuck)
X(bumpunstuck) \
X(public_key)
enum player_e
{
@ -1194,6 +1196,9 @@ static int player_get(lua_State *L)
case player_ping:
lua_pushinteger(L, playerpingtable[( plr - players )]);
break;
case player_public_key:
lua_pushstring(L, GetPrettyRRID(plr->public_key, false));
break;
case player_packetloss:
lua_pushinteger(L, playerpacketlosstable[plr - players]);
break;
@ -1949,8 +1954,7 @@ static int player_set(lua_State *L)
case player_botvars:
return NOSET;
case player_jointime:
plr->jointime = (tic_t)luaL_checkinteger(L, 3);
break;
return NOSET;
case player_spectatorreentry:
plr->spectatorreentry = (tic_t)luaL_checkinteger(L, 3);
break;

View file

@ -2589,3 +2589,27 @@ int M_RoundUp(double number)
return (int)number;
}
static char rrid_buf[256];
char *GetPrettyRRID(const unsigned char *bin, boolean brief)
{
size_t i;
size_t len = PUBKEYLENGTH;
if (brief)
len = 8;
if (bin == NULL || len == 0)
return NULL;
for (i=0; i<len; i++)
{
rrid_buf[i*2] = "0123456789ABCDEF"[bin[i] >> 4];
rrid_buf[i*2+1] = "0123456789ABCDEF"[bin[i] & 0x0F];
}
rrid_buf[len*2] = '\0';
return rrid_buf;
}

View file

@ -130,6 +130,8 @@ boolean M_IsStringEmpty(const char *s);
int M_RoundUp(double number);
char *GetPrettyRRID(const unsigned char *bin, boolean brief);
#include "w_wad.h"
extern char configfile[MAX_WADPATH];

View file

@ -0,0 +1,4 @@
target_sources(BLANKART PRIVATE
monocypher.c
monocypher.h
)

2938
src/monocypher/monocypher.c Normal file

File diff suppressed because it is too large Load diff

321
src/monocypher/monocypher.h Normal file
View file

@ -0,0 +1,321 @@
// Monocypher version 4.0.0
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
//
// The first licence is a regular 2-clause BSD licence. The second licence
// is the CC-0 from Creative Commons. It is intended to release Monocypher
// to the public domain. The BSD licence serves as a fallback option.
//
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
//
// ------------------------------------------------------------------------
//
// Copyright (c) 2017-2019, Loup Vaillant
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ------------------------------------------------------------------------
//
// Written in 2017-2019 by Loup Vaillant
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related 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
// <https://creativecommons.org/publicdomain/zero/1.0/>
#ifndef MONOCYPHER_H
#define MONOCYPHER_H
#include <stddef.h>
#include <stdint.h>
#ifdef MONOCYPHER_CPP_NAMESPACE
namespace MONOCYPHER_CPP_NAMESPACE {
#elif defined(__cplusplus)
extern "C" {
#endif
// Constant time comparisons
// -------------------------
// Return 0 if a and b are equal, -1 otherwise
int crypto_verify16(const uint8_t a[16], const uint8_t b[16]);
int crypto_verify32(const uint8_t a[32], const uint8_t b[32]);
int crypto_verify64(const uint8_t a[64], const uint8_t b[64]);
// Erase sensitive data
// --------------------
void crypto_wipe(void *secret, size_t size);
// Authenticated encryption
// ------------------------
void crypto_aead_lock(uint8_t *cipher_text,
uint8_t mac [16],
const uint8_t key [32],
const uint8_t nonce[24],
const uint8_t *ad, size_t ad_size,
const uint8_t *plain_text, size_t text_size);
int crypto_aead_unlock(uint8_t *plain_text,
const uint8_t mac [16],
const uint8_t key [32],
const uint8_t nonce[24],
const uint8_t *ad, size_t ad_size,
const uint8_t *cipher_text, size_t text_size);
// Authenticated stream
// --------------------
typedef struct {
uint64_t counter;
uint8_t key[32];
uint8_t nonce[8];
} crypto_aead_ctx;
void crypto_aead_init_x(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[24]);
void crypto_aead_init_djb(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[8]);
void crypto_aead_init_ietf(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[12]);
void crypto_aead_write(crypto_aead_ctx *ctx,
uint8_t *cipher_text,
uint8_t mac[16],
const uint8_t *ad , size_t ad_size,
const uint8_t *plain_text, size_t text_size);
int crypto_aead_read(crypto_aead_ctx *ctx,
uint8_t *plain_text,
const uint8_t mac[16],
const uint8_t *ad , size_t ad_size,
const uint8_t *cipher_text, size_t text_size);
// General purpose hash (BLAKE2b)
// ------------------------------
// Direct interface
void crypto_blake2b(uint8_t *hash, size_t hash_size,
const uint8_t *message, size_t message_size);
void crypto_blake2b_keyed(uint8_t *hash, size_t hash_size,
const uint8_t *key, size_t key_size,
const uint8_t *message, size_t message_size);
// Incremental interface
typedef struct {
// Do not rely on the size or contents of this type,
// for they may change without notice.
uint64_t hash[8];
uint64_t input_offset[2];
uint64_t input[16];
size_t input_idx;
size_t hash_size;
} crypto_blake2b_ctx;
void crypto_blake2b_init(crypto_blake2b_ctx *ctx, size_t hash_size);
void crypto_blake2b_keyed_init(crypto_blake2b_ctx *ctx, size_t hash_size,
const uint8_t *key, size_t key_size);
void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_blake2b_final(crypto_blake2b_ctx *ctx, uint8_t *hash);
// Password key derivation (Argon2)
// --------------------------------
#define CRYPTO_ARGON2_D 0
#define CRYPTO_ARGON2_I 1
#define CRYPTO_ARGON2_ID 2
typedef struct {
uint32_t algorithm; // Argon2d, Argon2i, Argon2id
uint32_t nb_blocks; // memory hardness, >= 8 * nb_lanes
uint32_t nb_passes; // CPU hardness, >= 1 (>= 3 recommended for Argon2i)
uint32_t nb_lanes; // parallelism level (single threaded anyway)
} crypto_argon2_config;
typedef struct {
const uint8_t *pass;
const uint8_t *salt;
uint32_t pass_size;
uint32_t salt_size; // 16 bytes recommended
} crypto_argon2_inputs;
typedef struct {
const uint8_t *key; // may be NULL if no key
const uint8_t *ad; // may be NULL if no additional data
uint32_t key_size; // 0 if no key (32 bytes recommended otherwise)
uint32_t ad_size; // 0 if no additional data
} crypto_argon2_extras;
extern const crypto_argon2_extras crypto_argon2_no_extras;
void crypto_argon2(uint8_t *hash, uint32_t hash_size, void *work_area,
crypto_argon2_config config,
crypto_argon2_inputs inputs,
crypto_argon2_extras extras);
// Key exchange (X-25519)
// ----------------------
// Shared secrets are not quite random.
// Hash them to derive an actual shared key.
void crypto_x25519_public_key(uint8_t public_key[32],
const uint8_t secret_key[32]);
void crypto_x25519(uint8_t raw_shared_secret[32],
const uint8_t your_secret_key [32],
const uint8_t their_public_key [32]);
// Conversion to EdDSA
void crypto_x25519_to_eddsa(uint8_t eddsa[32], const uint8_t x25519[32]);
// scalar "division"
// Used for OPRF. Be aware that exponential blinding is less secure
// than Diffie-Hellman key exchange.
void crypto_x25519_inverse(uint8_t blind_salt [32],
const uint8_t private_key[32],
const uint8_t curve_point[32]);
// "Dirty" versions of x25519_public_key().
// Use with crypto_elligator_rev().
// Leaks 3 bits of the private key.
void crypto_x25519_dirty_small(uint8_t pk[32], const uint8_t sk[32]);
void crypto_x25519_dirty_fast (uint8_t pk[32], const uint8_t sk[32]);
// Signatures
// ----------
// EdDSA with curve25519 + BLAKE2b
void crypto_eddsa_key_pair(uint8_t secret_key[64],
uint8_t public_key[32],
uint8_t seed[32]);
void crypto_eddsa_sign(uint8_t signature [64],
const uint8_t secret_key[64],
const uint8_t *message, size_t message_size);
int crypto_eddsa_check(const uint8_t signature [64],
const uint8_t public_key[32],
const uint8_t *message, size_t message_size);
// Conversion to X25519
void crypto_eddsa_to_x25519(uint8_t x25519[32], const uint8_t eddsa[32]);
// EdDSA building blocks
void crypto_eddsa_trim_scalar(uint8_t out[32], const uint8_t in[32]);
void crypto_eddsa_reduce(uint8_t reduced[32], const uint8_t expanded[64]);
void crypto_eddsa_mul_add(uint8_t r[32],
const uint8_t a[32],
const uint8_t b[32],
const uint8_t c[32]);
void crypto_eddsa_scalarbase(uint8_t point[32], const uint8_t scalar[32]);
int crypto_eddsa_check_equation(const uint8_t signature[64],
const uint8_t public_key[32],
const uint8_t h_ram[32]);
// Chacha20
// --------
// Specialised hash.
// Used to hash X25519 shared secrets.
void crypto_chacha20_h(uint8_t out[32],
const uint8_t key[32],
const uint8_t in [16]);
// Unauthenticated stream cipher.
// Don't forget to add authentication.
uint64_t crypto_chacha20_djb(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[8],
uint64_t ctr);
uint32_t crypto_chacha20_ietf(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[12],
uint32_t ctr);
uint64_t crypto_chacha20_x(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[24],
uint64_t ctr);
// Poly 1305
// ---------
// This is a *one time* authenticator.
// Disclosing the mac reveals the key.
// See crypto_lock() on how to use it properly.
// Direct interface
void crypto_poly1305(uint8_t mac[16],
const uint8_t *message, size_t message_size,
const uint8_t key[32]);
// Incremental interface
typedef struct {
// Do not rely on the size or contents of this type,
// for they may change without notice.
uint8_t c[16]; // chunk of the message
size_t c_idx; // How many bytes are there in the chunk.
uint32_t r [4]; // constant multiplier (from the secret key)
uint32_t pad[4]; // random number added at the end (from the secret key)
uint32_t h [5]; // accumulated hash
} crypto_poly1305_ctx;
void crypto_poly1305_init (crypto_poly1305_ctx *ctx, const uint8_t key[32]);
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_poly1305_final (crypto_poly1305_ctx *ctx, uint8_t mac[16]);
// Elligator 2
// -----------
// Elligator mappings proper
void crypto_elligator_map(uint8_t curve [32], const uint8_t hidden[32]);
int crypto_elligator_rev(uint8_t hidden[32], const uint8_t curve [32],
uint8_t tweak);
// Easy to use key pair generation
void crypto_elligator_key_pair(uint8_t hidden[32], uint8_t secret_key[32],
uint8_t seed[32]);
#ifdef __cplusplus
}
#endif
#endif // MONOCYPHER_H

View file

@ -860,6 +860,8 @@ static void P_NetSyncPlayers(savebuffer_t *save)
SYNC(players[i].itemusecooldown);
SYNC(players[i].itemusecooldownmax);
P_SyncMem(save, players[i].public_key, PUBKEYLENGTH);
}
TracyCZoneEnd(__zone);
}

View file

@ -84,7 +84,7 @@ STUN_node (void)
return node;
}
static void
void
csprng
(
void * const buffer,

View file

@ -18,6 +18,8 @@ extern "C" {
typedef void (*stun_callback_t)(UINT32 address);
void csprng (void * const buffer, const size_t size);
void STUN_bind (stun_callback_t);
boolean STUN_got_response (const char * const buffer, const size_t size);

View file

@ -73,6 +73,11 @@ TYPEDEF (rewind_t);
TYPEDEF (netinfo_pak);
TYPEDEF (say_pak);
TYPEDEF (reqmapqueue_pak);
TYPEDEF (clientkey_pak);
TYPEDEF (serverchallenge_pak);
TYPEDEF (challengeall_pak);
TYPEDEF (responseall_pak);
TYPEDEF (resultsall_pak);
// d_event.h
TYPEDEF (event_t);