From 4e8aa087626e03094d4ebfe688dd209414702010 Mon Sep 17 00:00:00 2001 From: divverent Date: Tue, 19 Apr 2011 15:31:26 +0000 Subject: [PATCH] crypto: avoid generating control-like packets In non-AES mode, we now replace packets whose hash starts with FFFFFFFF by 7FFFFFFF, and 8000LLLL by 0000LLLL. When decoding, packets with these prefixes have two attempts. AES encrypted mode is unaffected by this, as there packets always start with a byte from 00 to 0F. Also, no longer whine about receiving packets that fail the HMAC test when the packets look like control packets (the NQ CONNECT packet DP sends when connecting sometimes was received in time for this to match). git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11068 d7cf8633-e32d-0410-b094-e92efae38249 ::stable-branch::merge=294762940c3d8fb26989ce5fa0f8d2588d5e5a2e --- crypto.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/crypto.c b/crypto.c index 4b9d3976..7ff8ff48 100644 --- a/crypto.c +++ b/crypto.c @@ -1309,9 +1309,14 @@ static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *d } } +// NOTE: we MUST avoid the following begins of the packet: +// 1. 0xFF, 0xFF, 0xFF, 0xFF +// 2. 0x80, 0x00, length/256, length%256 +// this luckily does NOT affect AES mode, where the first byte always is in the range from 0x00 to 0x0F const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len) { unsigned char h[32]; + int i; if(crypto->authenticated) { if(crypto->use_aes) @@ -1346,6 +1351,15 @@ const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t *len_dst = len_src + 16; memcpy(data_dst, h, 16); memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src); + + // handle the "avoid" conditions: + i = BuffBigLong(data_dst); + if( + (i == (int)0xFFFFFFFF) // avoid QW control packet + || + (i == (int)0x80000000 + (int)*len_dst) // avoid NQ control packet + ) + *(unsigned char *)data_dst ^= 0x80; // this will ALWAYS fix it } return data_dst; } @@ -1359,6 +1373,17 @@ const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t const void *Crypto_DecryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len) { unsigned char h[32]; + int i; + + // silently handle non-crypto packets + i = BuffBigLong(data_src); + if( + (i == (int)0xFFFFFFFF) // avoid QW control packet + || + (i == (int)0x80000000 + (int)len_src) // avoid NQ control packet + ) + return NULL; + if(crypto->authenticated) { if(crypto->use_aes) @@ -1413,11 +1438,31 @@ const void *Crypto_DecryptPacket(crypto_t *crypto, const void *data_src, size_t Com_HexDumpToConsole((const unsigned char *) data_src, len_src); return NULL; } + if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length { - Con_Printf("HMAC mismatch\n"); - Com_HexDumpToConsole((const unsigned char *) data_src, len_src); - return NULL; + // undo the "avoid conditions" + if( + (i == (int)0x7FFFFFFF) // avoided QW control packet + || + (i == (int)0x00000000 + (int)len_src) // avoided NQ control packet + ) + { + // do the avoidance on the hash too + h[0] ^= 0x80; + if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length + { + Con_Printf("HMAC mismatch\n"); + Com_HexDumpToConsole((const unsigned char *) data_src, len_src); + return NULL; + } + } + else + { + Con_Printf("HMAC mismatch\n"); + Com_HexDumpToConsole((const unsigned char *) data_src, len_src); + return NULL; + } } return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used } -- 2.39.2