int CEncryptedDatagramSocket::DecryptReceivedServer(uint8_t* pbyBufIn, int nBufLen, uint8_t **ppbyBufOut, uint32_t dwBaseKey, uint32_t /*dbgIP*/) { int nResult = nBufLen; *ppbyBufOut = pbyBufIn; if (nResult <= CRYPT_HEADER_WITHOUTPADDING || !thePrefs::IsServerCryptLayerUDPEnabled() || dwBaseKey == 0) { return nResult; } if(pbyBufIn[0] == OP_EDONKEYPROT) { return nResult; // no encrypted packet (see description on top) } // might be an encrypted packet, try to decrypt uint8_t achKeyData[7]; PokeUInt32(achKeyData, dwBaseKey); achKeyData[4] = MAGICVALUE_UDP_SERVERCLIENT; memcpy(achKeyData + 5, pbyBufIn + 1, 2); // random key part sent from remote server CRC4EncryptableBuffer receivebuffer; MD5Sum md5(achKeyData, sizeof(achKeyData)); receivebuffer.SetKey(md5,true); uint32_t dwValue; receivebuffer.RC4Crypt(pbyBufIn + 3, (uint8_t*)&dwValue, sizeof(dwValue)); ENDIAN_SWAP_I_32(dwValue); if (dwValue == MAGICVALUE_UDP_SYNC_SERVER) { // yup this is an encrypted packet //DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from ServerIP: %s"), ipstr(dbgIP)) ); uint8_t byPadLen; receivebuffer.RC4Crypt(pbyBufIn + 7, (uint8_t*)&byPadLen, 1); byPadLen &= 15; nResult -= CRYPT_HEADER_WITHOUTPADDING; if (nResult <= byPadLen) { //DebugLogError(_T("Invalid obfuscated UDP packet from ServerIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dbgIP), byPadLen); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } if (byPadLen > 0) { receivebuffer.RC4Crypt(NULL, NULL, byPadLen); } nResult -= byPadLen; *ppbyBufOut = pbyBufIn + (nBufLen - nResult); receivebuffer.RC4Crypt((uint8_t*)*ppbyBufOut, (uint8_t*)*ppbyBufOut, nResult); theStats::AddDownOverheadCrypt(nBufLen - nResult); return nResult; // done } else { //DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from ServerIP: %s"), ipstr(dbgIP)); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } }
void CFileDataIO::WriteUInt32(uint32 value) { ENDIAN_SWAP_I_32(value); Write(&value, sizeof(uint32)); }
// Encrypt packet. Key used: // clientHashOrKadID != NULL -> clientHashOrKadID // clientHashOrKadID == NULL && kad && receiverVerifyKey != 0 -> receiverVerifyKey // else -> ASSERT int CEncryptedDatagramSocket::EncryptSendClient(uint8_t **buf, int bufLen, const uint8_t *clientHashOrKadID, bool kad, uint32_t receiverVerifyKey, uint32_t senderVerifyKey) { wxASSERT(theApp->GetPublicIP() != 0 || kad); wxASSERT(thePrefs::IsClientCryptLayerSupported()); wxASSERT(clientHashOrKadID != NULL || receiverVerifyKey != 0); wxASSERT((receiverVerifyKey == 0 && senderVerifyKey == 0) || kad); uint8_t padLen = 0; // padding disabled for UDP currently const uint32_t cryptHeaderLen = padLen + CRYPT_HEADER_WITHOUTPADDING + (kad ? 8 : 0); uint32_t cryptedLen = bufLen + cryptHeaderLen; uint8_t *cryptedBuffer = new uint8_t[cryptedLen]; bool kadRecvKeyUsed = false; uint16_t randomKeyPart = GetRandomUint16(); CRC4EncryptableBuffer sendbuffer; MD5Sum md5; if (kad) { if ((clientHashOrKadID == NULL || CMD4Hash(clientHashOrKadID).IsEmpty()) && receiverVerifyKey != 0) { kadRecvKeyUsed = true; uint8_t keyData[6]; PokeUInt32(keyData, receiverVerifyKey); PokeUInt16(keyData+4, randomKeyPart); md5.Calculate(keyData, sizeof(keyData)); //DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by ReceiverKey (%u)"), nReceiverVerifyKey) ); } else if (clientHashOrKadID != NULL && !CMD4Hash(clientHashOrKadID).IsEmpty()) { uint8_t keyData[18]; md4cpy(keyData, clientHashOrKadID); PokeUInt16(keyData+16, randomKeyPart); md5.Calculate(keyData, sizeof(keyData)); //DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by Hash/NodeID %s"), md4str(pachClientHashOrKadID)) ); } else { delete [] cryptedBuffer; wxFAIL; return bufLen; } } else { uint8_t keyData[23]; md4cpy(keyData, clientHashOrKadID); PokeUInt32(keyData+16, theApp->GetPublicIP()); PokeUInt16(keyData+21, randomKeyPart); keyData[20] = MAGICVALUE_UDP; md5.Calculate(keyData, sizeof(keyData)); } sendbuffer.SetKey(md5, true); // create the semi random byte encryption header uint8_t semiRandomNotProtocolMarker = 0; int i; for (i = 0; i < 128; i++) { semiRandomNotProtocolMarker = GetRandomUint8(); semiRandomNotProtocolMarker = kad ? (semiRandomNotProtocolMarker & 0xFE) : (semiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit if (kad) { // set the ed2k/kad and nodeid/recvkey markerbit semiRandomNotProtocolMarker = kadRecvKeyUsed ? ((semiRandomNotProtocolMarker & 0xFE) | 0x02) : (semiRandomNotProtocolMarker & 0xFC); } else { // set the ed2k/kad marker bit semiRandomNotProtocolMarker = (semiRandomNotProtocolMarker | 0x01); } bool bOk = false; switch (semiRandomNotProtocolMarker) { // not allowed values case OP_EMULEPROT: case OP_KADEMLIAPACKEDPROT: case OP_KADEMLIAHEADER: case OP_UDPRESERVEDPROT1: case OP_UDPRESERVEDPROT2: case OP_PACKEDPROT: break; default: bOk = true; } if (bOk) { break; } } if (i >= 128) { // either we have _real_ bad luck or the randomgenerator is a bit messed up wxFAIL; semiRandomNotProtocolMarker = 0x01; } cryptedBuffer[0] = semiRandomNotProtocolMarker; PokeUInt16(cryptedBuffer + 1, randomKeyPart); uint32_t magicValue = ENDIAN_SWAP_32(MAGICVALUE_UDP_SYNC_CLIENT); sendbuffer.RC4Crypt((uint8_t*)&magicValue, cryptedBuffer + 3, 4); sendbuffer.RC4Crypt((uint8_t*)&padLen, cryptedBuffer + 7, 1); for (int j = 0; j < padLen; j++) { uint8_t byRand = (uint8_t)rand(); // they actually don't really need to be random, but it doesn't hurt either sendbuffer.RC4Crypt((uint8_t*)&byRand, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1); } if (kad) { ENDIAN_SWAP_I_32(receiverVerifyKey); ENDIAN_SWAP_I_32(senderVerifyKey); sendbuffer.RC4Crypt((uint8_t*)&receiverVerifyKey, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + padLen, 4); sendbuffer.RC4Crypt((uint8_t*)&senderVerifyKey, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + padLen + 4, 4); } sendbuffer.RC4Crypt(*buf, cryptedBuffer + cryptHeaderLen, bufLen); delete [] *buf; *buf = cryptedBuffer; theStats::AddUpOverheadCrypt(cryptedLen - bufLen); return cryptedLen; }
int CEncryptedDatagramSocket::DecryptReceivedClient(uint8_t *bufIn, int bufLen, uint8_t **bufOut, uint32_t ip, uint32_t *receiverVerifyKey, uint32_t *senderVerifyKey) { int result = bufLen; *bufOut = bufIn; if (receiverVerifyKey == NULL || senderVerifyKey == NULL) { wxFAIL; return result; } *receiverVerifyKey = 0; *senderVerifyKey = 0; if (result <= CRYPT_HEADER_WITHOUTPADDING /*|| !thePrefs.IsClientCryptLayerSupported()*/) { return result; } switch (bufIn[0]) { case OP_EMULEPROT: case OP_KADEMLIAPACKEDPROT: case OP_KADEMLIAHEADER: case OP_UDPRESERVEDPROT1: case OP_UDPRESERVEDPROT2: case OP_PACKEDPROT: return result; // no encrypted packet (see description on top) default: ; } // might be an encrypted packet, try to decrypt CRC4EncryptableBuffer receivebuffer; uint32_t value = 0; // check the marker bit which type this packet could be and which key to test first, this is only an indicator since old clients have it set random // see the header for marker bits explanation uint8_t currentTry = ((bufIn[0] & 0x03) == 3) ? 1 : (bufIn[0] & 0x03); uint8_t tries; if (Kademlia::CKademlia::GetPrefs() == NULL) { // if kad never run, no point in checking anything except for ed2k encryption tries = 1; currentTry = 1; } else { tries = 3; } bool kad = false; do { receivebuffer.FullReset(); tries--; MD5Sum md5; if (currentTry == 0) { // kad packet with NodeID as key kad = true; if (Kademlia::CKademlia::GetPrefs()) { uint8_t keyData[18]; Kademlia::CKademlia::GetPrefs()->GetKadID().StoreCryptValue((uint8_t *)&keyData); memcpy(keyData + 16, bufIn + 1, 2); // random key part sent from remote client md5.Calculate(keyData, sizeof(keyData)); } } else if (currentTry == 1) { // ed2k packet kad = false; uint8_t keyData[23]; md4cpy(keyData, thePrefs::GetUserHash().GetHash()); keyData[20] = MAGICVALUE_UDP; PokeUInt32(keyData + 16, ip); memcpy(keyData + 21, bufIn + 1, 2); // random key part sent from remote client md5.Calculate(keyData, sizeof(keyData)); } else if (currentTry == 2) { // kad packet with ReceiverKey as key kad = true; if (Kademlia::CKademlia::GetPrefs()) { uint8_t keyData[6]; PokeUInt32(keyData, Kademlia::CPrefs::GetUDPVerifyKey(ip)); memcpy(keyData + 4, bufIn + 1, 2); // random key part sent from remote client md5.Calculate(keyData, sizeof(keyData)); } } else { wxFAIL; } receivebuffer.SetKey(md5, true); receivebuffer.RC4Crypt(bufIn + 3, (uint8_t*)&value, sizeof(value)); ENDIAN_SWAP_I_32(value); currentTry = (currentTry + 1) % 3; } while (value != MAGICVALUE_UDP_SYNC_CLIENT && tries > 0); // try to decrypt as ed2k as well as kad packet if needed (max 3 rounds) if (value == MAGICVALUE_UDP_SYNC_CLIENT) { // yup this is an encrypted packet // // debugoutput notices // // the following cases are "allowed" but shouldn't happen given that there is only our implementation yet // if (bKad && (pbyBufIn[0] & 0x01) != 0) // DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, ed2k bit)"), ipstr(dwIP)); // else if (bKad && !bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) != 0) // DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, nodeid key, recvkey bit)"), ipstr(dwIP)); // else if (bKad && bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) == 0) // DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, recvkey key, nodeid bit)"), ipstr(dwIP)); uint8_t padLen; receivebuffer.RC4Crypt(bufIn + 7, (uint8_t*)&padLen, 1); result -= CRYPT_HEADER_WITHOUTPADDING; if (result <= padLen) { //DebugLogError(_T("Invalid obfuscated UDP packet from clientIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dwIP), byPadLen); return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk } if (padLen > 0) { receivebuffer.RC4Crypt(NULL, NULL, padLen); } result -= padLen; if (kad) { if (result <= 8) { //DebugLogError(_T("Obfuscated Kad packet with mismatching size (verify keys missing) received from clientIP: %s"), ipstr(dwIP)); return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk; } // read the verify keys receivebuffer.RC4Crypt(bufIn + CRYPT_HEADER_WITHOUTPADDING + padLen, (uint8_t*)receiverVerifyKey, 4); receivebuffer.RC4Crypt(bufIn + CRYPT_HEADER_WITHOUTPADDING + padLen + 4, (uint8_t*)senderVerifyKey, 4); ENDIAN_SWAP_I_32(*receiverVerifyKey); ENDIAN_SWAP_I_32(*senderVerifyKey); result -= 8; } *bufOut = bufIn + (bufLen - result); receivebuffer.RC4Crypt((uint8_t*)*bufOut, (uint8_t*)*bufOut, result); theStats::AddDownOverheadCrypt(bufLen - result); return result; // done } else { //DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s"), ipstr(dwIP)); return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk } }