int CEncryptedDatagramSocket::EncryptSendServer(uchar** ppbyBuf, int nBufLen, uint32 dwBaseKey) const{ ASSERT( thePrefs.IsServerCryptLayerUDPEnabled() ); ASSERT( dwBaseKey != 0 ); uint8 byPadLen = 0; // padding disabled for UDP currently uint32 nCryptedLen = nBufLen + byPadLen + CRYPT_HEADER_WITHOUTPADDING; uchar* pachCryptedBuffer = new uchar[nCryptedLen]; uint16 nRandomKeyPart = (uint16)cryptRandomGen.GenerateWord32(0x0000, 0xFFFF); uchar achKeyData[7]; memcpy(achKeyData, &dwBaseKey, 4); achKeyData[4] = MAGICVALUE_UDP_CLIENTSERVER; memcpy(achKeyData + 5, &nRandomKeyPart, 2); MD5Sum md5(achKeyData, sizeof(achKeyData)); RC4_Key_Struct keySendKey; RC4CreateKey(md5.GetRawHash(), 16, &keySendKey, true); // create the semi random byte encryption header uint8 bySemiRandomNotProtocolMarker = 0; int i; for (i = 0; i < 128; i++){ bySemiRandomNotProtocolMarker = cryptRandomGen.GenerateByte(); if (bySemiRandomNotProtocolMarker != OP_EDONKEYPROT) // not allowed values break; } if (i >= 128){ // either we have _real_ bad luck or the randomgenerator is a bit messed up ASSERT( false ); bySemiRandomNotProtocolMarker = 0x01; } uint32 dwMagicValue = MAGICVALUE_UDP_SYNC_SERVER; pachCryptedBuffer[0] = bySemiRandomNotProtocolMarker; memcpy(pachCryptedBuffer + 1, &nRandomKeyPart, 2); RC4Crypt((uchar*)&dwMagicValue, pachCryptedBuffer + 3, 4, &keySendKey); RC4Crypt((uchar*)&byPadLen, pachCryptedBuffer + 7, 1, &keySendKey); for (int j = 0; j < byPadLen; j++){ uint8 byRand = (uint8)rand(); // they actually dont really need to be random, but it doesn't hurts either RC4Crypt((uchar*)&byRand, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1, &keySendKey); } RC4Crypt(*ppbyBuf, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen, nBufLen, &keySendKey); delete[] *ppbyBuf; *ppbyBuf = pachCryptedBuffer; //Xman // Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter- /* theStats.AddUpDataOverheadCrypt(nCryptedLen - nBufLen); */ theApp.pBandWidthControl->AddeMuleOutObfuscationUDP(nCryptedLen - nBufLen); //Xman end return nCryptedLen; }
int CEncryptedDatagramSocket::DecryptReceivedServer(BYTE* pbyBufIn, int nBufLen, BYTE** ppbyBufOut, uint32 dwBaseKey, uint32 dbgIP) const{ 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 uchar achKeyData[7]; memcpy(achKeyData, &dwBaseKey, 4); achKeyData[4] = MAGICVALUE_UDP_SERVERCLIENT; memcpy(achKeyData + 5, pbyBufIn + 1, 2); // random key part sent from remote server MD5Sum md5(achKeyData, sizeof(achKeyData)); RC4_Key_Struct keyReceiveKey; RC4CreateKey(md5.GetRawHash(), 16, &keyReceiveKey, true); uint32 dwValue; RC4Crypt(pbyBufIn + 3, (uchar*)&dwValue, sizeof(dwValue), &keyReceiveKey); if (dwValue == MAGICVALUE_UDP_SYNC_SERVER){ // yup this is an encrypted packet if (thePrefs.GetDebugServerUDPLevel() > 0) DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from ServerIP: %s"), ipstr(dbgIP)) ); uint8 byPadLen; RC4Crypt(pbyBufIn + 7, (uchar*)&byPadLen, 1, &keyReceiveKey); 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) RC4Crypt(NULL, NULL, byPadLen, &keyReceiveKey); nResult -= byPadLen; *ppbyBufOut = pbyBufIn + (nBufLen - nResult); RC4Crypt((uchar*)*ppbyBufOut, (uchar*)*ppbyBufOut, nResult, &keyReceiveKey); //Xman // Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter- /* theStats.AddDownDataOverheadCrypt(nBufLen - nResult); */ theApp.pBandWidthControl->AddeMuleInObfuscation(nBufLen - nResult); //Xman end 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 } }
int CEncryptedDatagramSocket::DecryptReceivedClient(BYTE* pbyBufIn, int nBufLen, BYTE** ppbyBufOut, uint32 dwIP) const{ int nResult = nBufLen; *ppbyBufOut = pbyBufIn; if (nResult <= CRYPT_HEADER_WITHOUTPADDING || !thePrefs.IsClientCryptLayerSupported()) return nResult; switch (pbyBufIn[0]){ case OP_EMULEPROT: case OP_KADEMLIAPACKEDPROT: case OP_KADEMLIAHEADER: case OP_UDPRESERVEDPROT1: case OP_UDPRESERVEDPROT2: case OP_PACKEDPROT: return nResult; // no encrypted packet (see description on top) } // might be an encrypted packet, try to decrypt uchar achKeyData[23]; md4cpy(achKeyData, thePrefs.GetUserHash()); achKeyData[20] = MAGICVALUE_UDP; memcpy(achKeyData + 16, &dwIP, 4); memcpy(achKeyData + 21, pbyBufIn + 1, 2); // random key part sent from remote client MD5Sum md5(achKeyData, sizeof(achKeyData)); RC4_Key_Struct keyReceiveKey; RC4CreateKey(md5.GetRawHash(), 16, &keyReceiveKey, true); uint32 dwValue; RC4Crypt(pbyBufIn + 3, (uchar*)&dwValue, sizeof(dwValue), &keyReceiveKey); if (dwValue == MAGICVALUE_UDP_SYNC_CLIENT){ // yup this is an encrypted packet DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from clientIP: %s"), ipstr(dwIP)) ); uint8 byPadLen; RC4Crypt(pbyBufIn + 7, (uchar*)&byPadLen, 1, &keyReceiveKey); nResult -= CRYPT_HEADER_WITHOUTPADDING; if (nResult <= byPadLen){ DebugLogError(_T("Invalid obfuscated UDP packet from clientIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dwIP), byPadLen); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } if (byPadLen > 0) RC4Crypt(NULL, NULL, byPadLen, &keyReceiveKey); nResult -= byPadLen; *ppbyBufOut = pbyBufIn + (nBufLen - nResult); RC4Crypt((uchar*)*ppbyBufOut, (uchar*)*ppbyBufOut, nResult, &keyReceiveKey); theStats.AddDownDataOverheadCrypt(nBufLen - nResult); return nResult; // done } else{ DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s"), ipstr(dwIP)); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } }
void WardenParseCommand5(char *data, int len, int index) { __int32 buf32; unsigned char tmpkey[0x102]; if (!lpwdnFnTable) return; if (!lpwdnFnTable->wdnGenKeys) { AddChat(vbRed, "Unable to generate new RC4 keys (wdnGenKeys == NULL)!", bot[index]->hWnd_rtfChat); return; } newrc4 = NULL; __asm { push 4 push offset wdnkeyseed mov ecx, lpWdnModClass mov eax, lpwdnFnTable //call dword ptr [eax] call [eax]WARDENFNTABLE.wdnGenKeys } if (!newrc4) { AddChat(vbRed, "wdnGenKeys() failed!", bot[index]->hWnd_rtfChat); return; } char *tmpdata = (char *)malloc(len); memcpy(tmpdata, data, len); memcpy(tmpkey, newrc4 + 0x102, sizeof(tmpkey)); RC4Crypt(tmpkey, (unsigned char *)tmpdata, len); memcpy(tmpkey, newrc4, sizeof(tmpkey)); if (pendingwpacket) { free(pendingwpacket); pendingwpacket = NULL; } __asm { lea eax, [buf32] push eax push len push tmpdata mov ecx, lpWdnModClass mov eax, lpwdnFnTable //call dword ptr [eax + 8] call [eax]WARDENFNTABLE.wdnHandlePacket } if (!pendingwpacket) { AddChat(vbRed, "wdnSendPacket() failed!", bot[index]->hWnd_rtfChat); return; } RC4Crypt(tmpkey, (unsigned char *)pendingwpacket, pendingwpacketlen); RC4Crypt((unsigned char *)bot[index]->wardenkey_out, (unsigned char *)pendingwpacket, pendingwpacketlen); memcpy(bot[index]->wardenkey_out, newrc4, 0x102); memcpy(bot[index]->wardenkey_in, (char *)newrc4 + 0x102, 0x102); InsertVoid(pendingwpacket, pendingwpacketlen); SendPacket(0x5E, index); }
void WardenParseCommand1(char *data, int len, int index) { char buf[128]; if (rawmodule) { memcpy(rawmodule + moddlprog, data + 3, *(__int16 *)(data + 1)); moddlprog += *(__int16 *)(data + 1); //sprintf(buf, "%d/%d bytes (%d%%)", moddlprog, modsize, // int((float)moddlprog / (float)modsize * 100.f)); //AddChat(vbGreen, buf, bot[index]->hWnd_rtfChat); } if (moddlprog >= modsize) { dling = 0; sprintf(buf, "Module downloaded, dl @ %d kB/s", (int)((float)(modsize) / (float)(GetTickCount() - startedtick))); AddChat(vbGreen, buf, bot[index]->hWnd_rtfChat); int fail = WardenDecryptInflateModule(modname, rawmodule, modsize, moddecryptkey, index); if (fail) { sprintf(buf, "Warden module decryption/inflation failure %d (%s).", fail, wextracterrstrs[fail - 1]); AddChat(vbRed, buf, bot[index]->hWnd_rtfChat); } else { WardenPrepareModule(modname); WardenModuleInitalize((LPWMODHEADER)currentmodule); *buf = 1; RC4Crypt(bot[index]->wardenkey_out, (unsigned char *)buf, 1); InsertByte(*buf); SendPacket(0x5E, index); } } }
int CEncryptedStreamSocket::SendNegotiatingData(const void* lpBuf, uint32_t nBufLen, uint32_t nStartCryptFromByte, bool bDelaySend){ ASSERT( m_StreamCryptState == ECS_NEGOTIATING || m_StreamCryptState == ECS_ENCRYPTING ); ASSERT( nStartCryptFromByte <= nBufLen ); ASSERT( m_NegotiatingState == ONS_BASIC_SERVER_DELAYEDSENDING || !bDelaySend ); BYTE* pBuffer = NULL; bool bProcess = false; if (lpBuf != NULL){ pBuffer = (BYTE*)malloc(nBufLen); if (pBuffer == NULL) AfxThrowMemoryException(); if (nStartCryptFromByte > 0) memcpy(pBuffer, lpBuf, nStartCryptFromByte); if (nBufLen > nStartCryptFromByte) RC4Crypt((uchar*)lpBuf + nStartCryptFromByte, pBuffer + nStartCryptFromByte, nBufLen - nStartCryptFromByte, m_pRC4SendKey); if (m_pfiSendBuffer != NULL){ // we already have data pending. Attach it and try to send if (m_NegotiatingState == ONS_BASIC_SERVER_DELAYEDSENDING) m_NegotiatingState = ONS_COMPLETE; else ASSERT( false ); m_pfiSendBuffer->SeekToEnd(); m_pfiSendBuffer->Write(pBuffer, nBufLen); free(pBuffer); pBuffer = NULL; nStartCryptFromByte = 0; bProcess = true; // we want to try to send it right now } } if (lpBuf == NULL || bProcess){ // this call is for processing pending data if (m_pfiSendBuffer == NULL || nStartCryptFromByte != 0){ ASSERT( false ); return 0; // or not } nBufLen = (uint32_t)m_pfiSendBuffer->GetLength(); pBuffer = m_pfiSendBuffer->Detach(); delete m_pfiSendBuffer; m_pfiSendBuffer = NULL; } ASSERT( m_pfiSendBuffer == NULL ); uint32_t result = 0; if (!bDelaySend) result = CAsyncSocketEx::Send(pBuffer, nBufLen); if (result == (uint32_t)SOCKET_ERROR || bDelaySend){ m_pfiSendBuffer = new CSafeMemFile(128); m_pfiSendBuffer->Write(pBuffer, nBufLen); free(pBuffer); return result; } else { if (result < nBufLen){ m_pfiSendBuffer = new CSafeMemFile(128); m_pfiSendBuffer->Write(pBuffer + result, nBufLen - result); } free(pBuffer); return result; } }
void CEncryptedStreamSocket::CryptPrepareSendData(uchar* pBuffer, uint32_t nLen){ if (!IsEncryptionLayerReady()){ ASSERT( false ); // must be a bug return; } if (m_StreamCryptState == ECS_UNKNOWN){ //this happens when the encryption option was not set on a outgoing connection //or if we try to send before receiving on a incoming connection - both shouldn't happen m_StreamCryptState = ECS_NONE; DebugLogError(_T("CEncryptedStreamSocket: Overwriting State ECS_UNKNOWN with ECS_NONE because of premature Send() (%s)"), DbgGetIPString()); } if (m_StreamCryptState == ECS_ENCRYPTING) RC4Crypt(pBuffer, pBuffer, nLen, m_pRC4SendKey); }
int WardenDecryptInflateModule(char *modulename, char *module, int modulelen, char *keyseed, int index) { unsigned long byts; unsigned char cryptkey[0x102]; MD5((char *)module, modulelen, (char *)cryptkey); if (memcmp(modhash, cryptkey, 16)) return 1; WardenKeyGenerate(cryptkey, (unsigned char *)keyseed, 0x10); RC4Crypt(cryptkey, (unsigned char *)module, modulelen); if (*(int *)(module + modulelen - 0x104) != 'SIGN') return 2; unsigned long extlen = *(int *)module; char *extmodule = (char *)malloc(extlen); if (uncompress((unsigned char *)extmodule, &extlen, (unsigned char *)module + 4, modulelen - 4)) { free(extmodule); return 3; } HANDLE hFile = CreateFile(modulename, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { free(extmodule); return 4; } if (!WriteFile(hFile, extmodule, extlen, &byts, NULL)) { free(extmodule); CloseHandle(hFile); return 5; } free(extmodule); CloseHandle(hFile); return 0; }
void Parse0x5E(char *data, int index) { char buf[128]; unsigned int len = *(short *)(data + 2) - 4; data += 4; RC4Crypt(bot[index]->wardenkey_in, (unsigned char *)data, len); switch (data[0]) { case 0: WardenParseCommand0(data, len, index); break; case 1: WardenParseCommand1(data, len, index); break; case 2: WardenParseCommand2(data, len, index); break; case 5: WardenParseCommand5(data, len, index); break; default: sprintf(buf, "Unhandled warden command 0x%02x!", (unsigned char)data[0]); AddChat(vbRed, buf, bot[index]->hWnd_rtfChat); StrToHexOut(data, len, bot[index]->hWnd_rtfChat); } }
void WardenParseCommand2(char *data, int len, int index) { char buf[512]; char asdf[64]; char *tosend = buf + 7; char *mods[8]; void *address; int pos = 1, nummods = 0, length, lentoread; ZeroMemory(buf, sizeof(buf)); //StrToHexOut(data, len, hWnd_status_re); while (data[pos]) { mods[nummods] = (char *)malloc(data[pos] + 1); memcpy(mods[nummods], data + pos + 1, data[pos]); *(mods[nummods] + data[pos]) = 0; nummods++; pos = pos + data[pos] + 1; if (nummods == 8) break; } pos++; int wc3 = ((bot[index]->fstate & BFS_WARCRAFT3) && 1); /////////////////// //if (!lpModuleImage[wc3]) { // AddChat(vbRed, "Requested module is not loaded!", bot[index]->hWnd_rtfChat); // goto freenret; //} while (pos + 1 < len) { //data[i] ^= data[len - 1]; if (pos >= 256) { AddChat(vbRed, "WARNING! WARDEN BUFFER OVER THRESHHOLD!", bot[index]->hWnd_rtfChat); break; } pos++; //skip command id if ((unsigned char)data[pos] <= nummods && !data[pos + 4]) { //memcheck /* (BYTE) String Index (DWORD) Address (BYTE) Length to Read */ //mods[data[pos]]; //address = *(__int32 *)(data + pos + 1) - (data[pos] ? 0 : 0x400000) + lpModuleImage[wc3]; address = GetAddress(*(void **)(data + pos + 1), mods, data[pos], nummods, wc3); if (address) { lentoread = data[pos + 5]; if (IsBadReadPtr(address, lentoread)) { AddChatf(asdf, hWnd_status_re, vbRed, "[%d] Unreadable memcheck, addr 0x%08x, len %d. at pos %d!", index, address, lentoread, pos); StrToHexOut(data, len, hWnd_status_re); goto pagecheck; } *tosend++ = 0; memcpy(tosend, address, lentoread); tosend += lentoread; } else { AddChatf(asdf, hWnd_status_re, vbRed, "[%d] Unreadable memcheck, addr 0x%08x, len %d. at pos %d!", index, address, lentoread, pos); StrToHexOut(data, len, hWnd_status_re); goto pagecheck; } pos += 6; } else { //pagecheck pagecheck: /* (DWORD) Seed (DWORD)[5] SHA1 (DWORD) Address (BYTE) Length to Read */ *tosend = (char)0xE9; //0; tosend++; pos += 29; } } length = tosend - buf; *buf = 2; *(__int16 *)(buf + 1) = length - 7; *(__int32 *)(buf + 3) = WardenGenerateChecksum(buf + 7, length - 7); RC4Crypt(bot[index]->wardenkey_out, (unsigned char *)buf, length); InsertVoid(buf, length); SendPacket(0x5E, index); //freenret: while (nummods--) free(mods[nummods]); }
int CEncryptedStreamSocket::Negotiate(const uchar* pBuffer, uint32_t nLen){ uint32_t nRead = 0; ASSERT( m_nReceiveBytesWanted > 0 ); try{ while (m_NegotiatingState != ONS_COMPLETE && m_nReceiveBytesWanted > 0){ if (m_nReceiveBytesWanted > 512){ ASSERT( false ); return 0; } if (m_pfiReceiveBuffer == NULL){ BYTE* pReceiveBuffer = (BYTE*)malloc(512); // use a fixed size buffer if (pReceiveBuffer == NULL) AfxThrowMemoryException(); m_pfiReceiveBuffer = new CSafeMemFile(pReceiveBuffer, 512); } const uint32_t nToRead = min(nLen - nRead, m_nReceiveBytesWanted); m_pfiReceiveBuffer->Write(pBuffer + nRead, nToRead); nRead += nToRead; m_nReceiveBytesWanted -= nToRead; if (m_nReceiveBytesWanted > 0) return nRead; const uint32_t nCurrentBytesLen = (uint32_t)m_pfiReceiveBuffer->GetPosition(); if (m_NegotiatingState != ONS_BASIC_CLIENTA_RANDOMPART && m_NegotiatingState != ONS_BASIC_SERVER_DHANSWER){ // don't have the keys yet BYTE* pCryptBuffer = m_pfiReceiveBuffer->Detach(); RC4Crypt(pCryptBuffer, pCryptBuffer, nCurrentBytesLen, m_pRC4ReceiveKey); m_pfiReceiveBuffer->Attach(pCryptBuffer, 512); } m_pfiReceiveBuffer->SeekToBegin(); switch (m_NegotiatingState){ case ONS_NONE: // would be a bug ASSERT( false ); return 0; case ONS_BASIC_CLIENTA_RANDOMPART:{ ASSERT( m_pRC4ReceiveKey == NULL ); uchar achKeyData[21]; md4cpy(achKeyData, thePrefs.GetUserHash()); achKeyData[16] = MAGICVALUE_REQUESTER; m_pfiReceiveBuffer->Read(achKeyData + 17, 4); // random key part sent from remote client MD5Sum md5(achKeyData, sizeof(achKeyData)); m_pRC4ReceiveKey = RC4CreateKey(md5.GetRawHash(), 16, NULL); achKeyData[16] = MAGICVALUE_SERVER; md5.Calculate(achKeyData, sizeof(achKeyData)); m_pRC4SendKey = RC4CreateKey(md5.GetRawHash(), 16, NULL); m_NegotiatingState = ONS_BASIC_CLIENTA_MAGICVALUE; m_nReceiveBytesWanted = 4; break; } case ONS_BASIC_CLIENTA_MAGICVALUE:{ uint32_t dwValue = m_pfiReceiveBuffer->ReadUInt32(); if (dwValue == MAGICVALUE_SYNC){ // yup, the one or the other way it worked, this is an encrypted stream //DEBUG_ONLY( DebugLog(_T("Received proper magic value, clientIP: %s"), DbgGetIPString()) ); // set the receiver key m_NegotiatingState = ONS_BASIC_CLIENTA_METHODTAGSPADLEN; m_nReceiveBytesWanted = 3; } else{ DebugLogError(_T("CEncryptedStreamSocket: Received wrong magic value from clientIP %s on a supposly encrytped stream / Wrong Header"), DbgGetIPString()); OnError(ERR_ENCRYPTION); return (-1); } break; } case ONS_BASIC_CLIENTA_METHODTAGSPADLEN: m_dbgbyEncryptionSupported = m_pfiReceiveBuffer->ReadUInt8(); m_dbgbyEncryptionRequested = m_pfiReceiveBuffer->ReadUInt8(); if (m_dbgbyEncryptionRequested != ENM_OBFUSCATION) AddDebugLogLine(DLP_LOW, false, _T("CEncryptedStreamSocket: Client %s preffered unsupported encryption method (%i)"), DbgGetIPString(), m_dbgbyEncryptionRequested); m_nReceiveBytesWanted = m_pfiReceiveBuffer->ReadUInt8(); m_NegotiatingState = ONS_BASIC_CLIENTA_PADDING; //if (m_nReceiveBytesWanted > 16) // AddDebugLogLine(DLP_LOW, false, _T("CEncryptedStreamSocket: Client %s sent more than 16 (%i) padding bytes"), DbgGetIPString(), m_nReceiveBytesWanted); if (m_nReceiveBytesWanted > 0) break; case ONS_BASIC_CLIENTA_PADDING:{ // ignore the random bytes, send the response, set status complete CSafeMemFile fileResponse(26); fileResponse.WriteUInt32(MAGICVALUE_SYNC); const uint8_t bySelectedEncryptionMethod = ENM_OBFUSCATION; // we do not support any further encryption in this version, so no need to look which the other client preferred fileResponse.WriteUInt8(bySelectedEncryptionMethod); SOCKADDR_IN sockAddr = {0}; int nSockAddrLen = sizeof(sockAddr); GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); const uint8_t byPaddingLen = theApp.serverconnect->AwaitingTestFromIP(sockAddr.sin_addr.S_un.S_addr) ? 16 : (thePrefs.GetCryptTCPPaddingLength() + 1); uint8_t byPadding = (uint8_t)(cryptRandomGen.GenerateByte() % byPaddingLen); fileResponse.WriteUInt8(byPadding); for (int i = 0; i < byPadding; i++) fileResponse.WriteUInt8(static_cast<uint8_t>(rand() & 0xFF)); SendNegotiatingData(fileResponse.GetBuffer(), (uint32_t)fileResponse.GetLength()); m_NegotiatingState = ONS_COMPLETE; m_StreamCryptState = ECS_ENCRYPTING; //DEBUG_ONLY( DebugLog(_T("CEncryptedStreamSocket: Finished Obufscation handshake with client %s (incoming)"), DbgGetIPString()) ); break; } case ONS_BASIC_CLIENTB_MAGICVALUE:{ if (m_pfiReceiveBuffer->ReadUInt32() != MAGICVALUE_SYNC){ DebugLogError(_T("CEncryptedStreamSocket: EncryptedstreamSyncError: Client sent wrong Magic Value as answer, cannot complete handshake (%s)"), DbgGetIPString()); OnError(ERR_ENCRYPTION); return (-1); } m_NegotiatingState = ONS_BASIC_CLIENTB_METHODTAGSPADLEN; m_nReceiveBytesWanted = 2; break; } case ONS_BASIC_CLIENTB_METHODTAGSPADLEN:{ m_dbgbyEncryptionMethodSet = m_pfiReceiveBuffer->ReadUInt8(); if (m_dbgbyEncryptionMethodSet != ENM_OBFUSCATION){ DebugLogError( _T("CEncryptedStreamSocket: Client %s set unsupported encryption method (%i), handshake failed"), DbgGetIPString(), m_dbgbyEncryptionMethodSet); OnError(ERR_ENCRYPTION); return (-1); } m_nReceiveBytesWanted = m_pfiReceiveBuffer->ReadUInt8(); m_NegotiatingState = ONS_BASIC_CLIENTB_PADDING; if (m_nReceiveBytesWanted > 0) break; } case ONS_BASIC_CLIENTB_PADDING: // ignore the random bytes, the handshake is complete m_NegotiatingState = ONS_COMPLETE; m_StreamCryptState = ECS_ENCRYPTING; //DEBUG_ONLY( DebugLog(_T("CEncryptedStreamSocket: Finished Obufscation handshake with client %s (outgoing)"), DbgGetIPString()) ); break; case ONS_BASIC_SERVER_DHANSWER:{ ASSERT( !m_cryptDHA.IsZero() ); uchar aBuffer[PRIMESIZE_BYTES + 1]; m_pfiReceiveBuffer->Read(aBuffer, PRIMESIZE_BYTES); CryptoPP::Integer cryptDHAnswer((byte*)aBuffer, PRIMESIZE_BYTES); CryptoPP::Integer cryptDHPrime((byte*)dh768_p, PRIMESIZE_BYTES); // our fixed prime CryptoPP::Integer cryptResult = CryptoPP::a_exp_b_mod_c(cryptDHAnswer, m_cryptDHA, cryptDHPrime); m_cryptDHA = 0; DEBUG_ONLY( ZeroMemory(aBuffer, sizeof(aBuffer)) ); ASSERT( cryptResult.MinEncodedSize() <= PRIMESIZE_BYTES ); // create the keys cryptResult.Encode(aBuffer, PRIMESIZE_BYTES); aBuffer[PRIMESIZE_BYTES] = MAGICVALUE_REQUESTER; MD5Sum md5(aBuffer, sizeof(aBuffer)); m_pRC4SendKey = RC4CreateKey(md5.GetRawHash(), 16, NULL); aBuffer[PRIMESIZE_BYTES] = MAGICVALUE_SERVER; md5.Calculate(aBuffer, sizeof(aBuffer)); m_pRC4ReceiveKey = RC4CreateKey(md5.GetRawHash(), 16, NULL); m_NegotiatingState = ONS_BASIC_SERVER_MAGICVALUE; m_nReceiveBytesWanted = 4; break; } case ONS_BASIC_SERVER_MAGICVALUE:{ uint32_t dwValue = m_pfiReceiveBuffer->ReadUInt32(); if (dwValue == MAGICVALUE_SYNC){ // yup, the one or the other way it worked, this is an encrypted stream DebugLog(_T("Received proper magic value after DH-Agreement from Serverconnection IP: %s"), DbgGetIPString()); // set the receiver key m_NegotiatingState = ONS_BASIC_SERVER_METHODTAGSPADLEN; m_nReceiveBytesWanted = 3; } else{ DebugLogError(_T("CEncryptedStreamSocket: Received wrong magic value after DH-Agreement from Serverconnection"), DbgGetIPString()); OnError(ERR_ENCRYPTION); return (-1); } break; } case ONS_BASIC_SERVER_METHODTAGSPADLEN: m_dbgbyEncryptionSupported = m_pfiReceiveBuffer->ReadUInt8(); m_dbgbyEncryptionRequested = m_pfiReceiveBuffer->ReadUInt8(); if (m_dbgbyEncryptionRequested != ENM_OBFUSCATION) AddDebugLogLine(DLP_LOW, false, _T("CEncryptedStreamSocket: Server %s preffered unsupported encryption method (%i)"), DbgGetIPString(), m_dbgbyEncryptionRequested); m_nReceiveBytesWanted = m_pfiReceiveBuffer->ReadUInt8(); m_NegotiatingState = ONS_BASIC_SERVER_PADDING; if (m_nReceiveBytesWanted > 16) AddDebugLogLine(DLP_LOW, false, _T("CEncryptedStreamSocket: Server %s sent more than 16 (%i) padding bytes"), DbgGetIPString(), m_nReceiveBytesWanted); if (m_nReceiveBytesWanted > 0) break; case ONS_BASIC_SERVER_PADDING:{ // ignore the random bytes (they are decrypted already), send the response, set status complete CSafeMemFile fileResponse(26); fileResponse.WriteUInt32(MAGICVALUE_SYNC); const uint8_t bySelectedEncryptionMethod = ENM_OBFUSCATION; // we do not support any further encryption in this version, so no need to look which the other client preferred fileResponse.WriteUInt8(bySelectedEncryptionMethod); uint8_t byPadding = (uint8_t)(cryptRandomGen.GenerateByte() % 16); fileResponse.WriteUInt8(byPadding); for (int i = 0; i < byPadding; i++) fileResponse.WriteUInt8(static_cast<uint8_t>(rand() & 0xFF)); m_NegotiatingState = ONS_BASIC_SERVER_DELAYEDSENDING; SendNegotiatingData(fileResponse.GetBuffer(), (uint32_t)fileResponse.GetLength(), 0, true); // don't actually send it right now, store it in our sendbuffer m_StreamCryptState = ECS_ENCRYPTING; DEBUG_ONLY( DebugLog(_T("CEncryptedStreamSocket: Finished DH Obufscation handshake with Server %s"), DbgGetIPString()) ); break; } default: ASSERT( false ); } m_pfiReceiveBuffer->SeekToBegin(); } if (m_pfiReceiveBuffer != NULL) free(m_pfiReceiveBuffer->Detach()); delete m_pfiReceiveBuffer; m_pfiReceiveBuffer = NULL; return nRead; } catch(CFileException* error){ // can only be caused by a bug in negationhandling, not by the datastream error->Delete(); ASSERT( false ); OnError(ERR_ENCRYPTION); if (m_pfiReceiveBuffer != NULL) free(m_pfiReceiveBuffer->Detach()); delete m_pfiReceiveBuffer; m_pfiReceiveBuffer = NULL; return (-1); } }
int CEncryptedDatagramSocket::DecryptReceivedClient(BYTE* pbyBufIn, int nBufLen, BYTE** ppbyBufOut, uint32 dwIP, uint32* nReceiverVerifyKey, uint32* nSenderVerifyKey) const{ int nResult = nBufLen; *ppbyBufOut = pbyBufIn; if (nReceiverVerifyKey == NULL || nSenderVerifyKey == NULL){ ASSERT( false ); return nResult; } *nReceiverVerifyKey = 0; *nSenderVerifyKey = 0; if (nResult <= CRYPT_HEADER_WITHOUTPADDING /*|| !thePrefs.IsClientCryptLayerSupported()*/) return nResult; switch (pbyBufIn[0]){ case OP_EMULEPROT: case OP_KADEMLIAPACKEDPROT: case OP_KADEMLIAHEADER: case OP_UDPRESERVEDPROT1: case OP_UDPRESERVEDPROT2: case OP_PACKEDPROT: return nResult; // no encrypted packet (see description on top) } // might be an encrypted packet, try to decrypt RC4_Key_Struct keyReceiveKey; uint32 dwValue = 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 byte byCurrentTry = ((pbyBufIn[0] & 0x03) == 3) ? 1 : (pbyBufIn[0] & 0x03); byte byTries; if (Kademlia::CKademlia::GetPrefs() == NULL) { // if kad never run, no point in checking anything except for ed2k encryption byTries = 1; byCurrentTry = 1; } else byTries = 3; bool bKadRecvKeyUsed = false; bool bKad = false; do{ byTries--; MD5Sum md5; if (byCurrentTry == 0) { // kad packet with NodeID as key bKad = true; bKadRecvKeyUsed = false; if (Kademlia::CKademlia::GetPrefs()) { uchar achKeyData[18]; memcpy(achKeyData, Kademlia::CKademlia::GetPrefs()->GetKadID().GetData(), 16); memcpy(achKeyData + 16, pbyBufIn + 1, 2); // random key part sent from remote client md5.Calculate(achKeyData, sizeof(achKeyData)); } } else if (byCurrentTry == 1) { // ed2k packet bKad = false; bKadRecvKeyUsed = false; uchar achKeyData[23]; md4cpy(achKeyData, thePrefs.GetUserHash()); achKeyData[20] = MAGICVALUE_UDP; memcpy(achKeyData + 16, &dwIP, 4); memcpy(achKeyData + 21, pbyBufIn + 1, 2); // random key part sent from remote client md5.Calculate(achKeyData, sizeof(achKeyData)); } else if (byCurrentTry == 2) { // kad packet with ReceiverKey as key bKad = true; bKadRecvKeyUsed = true; if (Kademlia::CKademlia::GetPrefs()) { uchar achKeyData[6]; PokeUInt32(achKeyData, Kademlia::CPrefs::GetUDPVerifyKey(dwIP)); memcpy(achKeyData + 4, pbyBufIn + 1, 2); // random key part sent from remote client md5.Calculate(achKeyData, sizeof(achKeyData)); } } else ASSERT( false ); RC4CreateKey(md5.GetRawHash(), 16, &keyReceiveKey, true); RC4Crypt(pbyBufIn + 3, (uchar*)&dwValue, sizeof(dwValue), &keyReceiveKey); byCurrentTry = (byCurrentTry + 1) % 3; } while (dwValue != MAGICVALUE_UDP_SYNC_CLIENT && byTries > 0); // try to decrypt as ed2k as well as kad packet if needed (max 3 rounds) if (dwValue == 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 byPadLen; RC4Crypt(pbyBufIn + 7, (uchar*)&byPadLen, 1, &keyReceiveKey); nResult -= CRYPT_HEADER_WITHOUTPADDING; if (nResult <= byPadLen){ DebugLogError(_T("Invalid obfuscated UDP packet from clientIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dwIP), byPadLen); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } if (byPadLen > 0) RC4Crypt(NULL, NULL, byPadLen, &keyReceiveKey); nResult -= byPadLen; if (bKad){ if (nResult <= 8){ DebugLogError(_T("Obfuscated Kad packet with mismatching size (verify keys missing) received from clientIP: %s"), ipstr(dwIP)); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk; } // read the verify keys RC4Crypt(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen, (uchar*)nReceiverVerifyKey, 4, &keyReceiveKey); RC4Crypt(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 4, (uchar*)nSenderVerifyKey, 4, &keyReceiveKey); nResult -= 8; } *ppbyBufOut = pbyBufIn + (nBufLen - nResult); RC4Crypt((uchar*)*ppbyBufOut, (uchar*)*ppbyBufOut, nResult, &keyReceiveKey); //Xman // Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter- /* theStats.AddDownDataOverheadCrypt(nBufLen - nResult); */ theApp.pBandWidthControl->AddeMuleInObfuscation(nBufLen - nResult); //Xman end //DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from clientIP: %s, Key: %s, RKey: %u, SKey: %u"), ipstr(dwIP), bKad ? (bKadRecvKeyUsed ? _T("ReceiverKey") : _T("NodeID")) : _T("UserHash") // , nReceiverVerifyKey != 0 ? *nReceiverVerifyKey : 0, nSenderVerifyKey != 0 ? *nSenderVerifyKey : 0) ); return nResult; // done } else{ DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s, Possible RecvKey: %u"), ipstr(dwIP), Kademlia::CPrefs::GetUDPVerifyKey(dwIP)); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } }
// Encrypt packet. Key used: // pachClientHashOrKadID != NULL -> pachClientHashOrKadID // pachClientHashOrKadID == NULL && bKad && nReceiverVerifyKey != 0 -> nReceiverVerifyKey // else -> ASSERT int CEncryptedDatagramSocket::EncryptSendClient(uchar** ppbyBuf, int nBufLen, const uchar* pachClientHashOrKadID, bool bKad, uint32 nReceiverVerifyKey, uint32 nSenderVerifyKey) const{ ASSERT( theApp.GetPublicIP() != 0 || bKad ); ASSERT( thePrefs.IsClientCryptLayerSupported() ); ASSERT( pachClientHashOrKadID != NULL || nReceiverVerifyKey != 0 ); ASSERT( (nReceiverVerifyKey == 0 && nSenderVerifyKey == 0) || bKad ); uint8 byPadLen = 0; // padding disabled for UDP currently const uint32 nCryptHeaderLen = byPadLen + CRYPT_HEADER_WITHOUTPADDING + (bKad ? 8 : 0); uint32 nCryptedLen = nBufLen + nCryptHeaderLen; uchar* pachCryptedBuffer = new uchar[nCryptedLen]; bool bKadRecKeyUsed = false; uint16 nRandomKeyPart = (uint16)cryptRandomGen.GenerateWord32(0x0000, 0xFFFF); MD5Sum md5; if (bKad){ if ((pachClientHashOrKadID == NULL || isnulmd4(pachClientHashOrKadID)) && nReceiverVerifyKey != 0) { bKadRecKeyUsed = true; uchar achKeyData[6]; PokeUInt32(achKeyData, nReceiverVerifyKey); PokeUInt16(achKeyData+4, nRandomKeyPart); md5.Calculate(achKeyData, sizeof(achKeyData)); //DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by ReceiverKey (%u)"), nReceiverVerifyKey) ); } else if (pachClientHashOrKadID != NULL && !isnulmd4(pachClientHashOrKadID)) { uchar achKeyData[18]; md4cpy(achKeyData, pachClientHashOrKadID); PokeUInt16(achKeyData+16, nRandomKeyPart); md5.Calculate(achKeyData, sizeof(achKeyData)); //DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by Hash/NodeID %s"), md4str(pachClientHashOrKadID)) ); } else { ASSERT( false ); delete[] pachCryptedBuffer; return nBufLen; } } else{ uchar achKeyData[23]; md4cpy(achKeyData, pachClientHashOrKadID); uint32 dwIP = theApp.GetPublicIP(); memcpy(achKeyData+16, &dwIP, 4); memcpy(achKeyData+21, &nRandomKeyPart, 2); achKeyData[20] = MAGICVALUE_UDP; md5.Calculate(achKeyData, sizeof(achKeyData)); } RC4_Key_Struct keySendKey; RC4CreateKey(md5.GetRawHash(), 16, &keySendKey, true); // create the semi random byte encryption header uint8 bySemiRandomNotProtocolMarker = 0; int i; for (i = 0; i < 128; i++){ bySemiRandomNotProtocolMarker = cryptRandomGen.GenerateByte(); bySemiRandomNotProtocolMarker = bKad ? (bySemiRandomNotProtocolMarker & 0xFE) : (bySemiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit if (bKad) bySemiRandomNotProtocolMarker = bKadRecKeyUsed ? ((bySemiRandomNotProtocolMarker & 0xFE) | 0x02) : (bySemiRandomNotProtocolMarker & 0xFC); // set the ed2k/kad and nodeid/reckey markerbit else bySemiRandomNotProtocolMarker = (bySemiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit bool bOk = false; switch (bySemiRandomNotProtocolMarker){ // 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 _really_ bad luck or the randomgenerator is a bit messed up ASSERT( false ); bySemiRandomNotProtocolMarker = 0x01; } uint32 dwMagicValue = MAGICVALUE_UDP_SYNC_CLIENT; pachCryptedBuffer[0] = bySemiRandomNotProtocolMarker; memcpy(pachCryptedBuffer + 1, &nRandomKeyPart, 2); RC4Crypt((uchar*)&dwMagicValue, pachCryptedBuffer + 3, 4, &keySendKey); RC4Crypt((uchar*)&byPadLen, pachCryptedBuffer + 7, 1, &keySendKey); for (int j = 0; j < byPadLen; j++){ uint8 byRand = (uint8)rand(); // they actually dont really need to be random, but it doesn't hurts either RC4Crypt((uchar*)&byRand, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1, &keySendKey); } if (bKad){ RC4Crypt((uchar*)&nReceiverVerifyKey, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen, 4, &keySendKey); RC4Crypt((uchar*)&nSenderVerifyKey, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 4, 4, &keySendKey); } RC4Crypt(*ppbyBuf, pachCryptedBuffer + nCryptHeaderLen, nBufLen, &keySendKey); delete[] *ppbyBuf; *ppbyBuf = pachCryptedBuffer; //Xman // Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter- /* theStats.AddUpDataOverheadCrypt(nCryptedLen - nBufLen); */ theApp.pBandWidthControl->AddeMuleOutObfuscationUDP(nCryptedLen - nBufLen); //Xman end return nCryptedLen; }
int CEncryptedDatagramSocket::EncryptSendClient(uchar** ppbyBuf, int nBufLen, const uchar* pachClientHashOrKadID, bool bKad, uint16 nReceiverVerifyKey, uint16 nSenderVerifyKey) const{ ASSERT( theApp.GetPublicIP() != 0 || bKad ); ASSERT( thePrefs.IsClientCryptLayerSupported() ); uint8 byPadLen = 0; // padding disabled for UDP currently const uint32 nCryptHeaderLen = byPadLen + CRYPT_HEADER_WITHOUTPADDING + (bKad ? 4 : 0); uint32 nCryptedLen = nBufLen + nCryptHeaderLen; uchar* pachCryptedBuffer = new uchar[nCryptedLen]; uint16 nRandomKeyPart = (uint16)cryptRandomGen.GenerateWord32(0x0000, 0xFFFF); MD5Sum md5; if (bKad){ uchar achKeyData[18]; md4cpy(achKeyData, pachClientHashOrKadID); memcpy(achKeyData+16, &nRandomKeyPart, 2); md5.Calculate(achKeyData, sizeof(achKeyData)); } else{ uchar achKeyData[23]; md4cpy(achKeyData, pachClientHashOrKadID); uint32 dwIP = theApp.GetPublicIP(); memcpy(achKeyData+16, &dwIP, 4); memcpy(achKeyData+21, &nRandomKeyPart, 2); achKeyData[20] = MAGICVALUE_UDP; md5.Calculate(achKeyData, sizeof(achKeyData)); } RC4_Key_Struct keySendKey; RC4CreateKey(md5.GetRawHash(), 16, &keySendKey, true); // create the semi random byte encryption header uint8 bySemiRandomNotProtocolMarker = 0; int i; for (i = 0; i < 128; i++){ bySemiRandomNotProtocolMarker = cryptRandomGen.GenerateByte(); bySemiRandomNotProtocolMarker = bKad ? (bySemiRandomNotProtocolMarker & 0xFE) : (bySemiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit bool bOk = false; switch (bySemiRandomNotProtocolMarker){ // 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 ASSERT( false ); bySemiRandomNotProtocolMarker = 0x01; } uint32 dwMagicValue = MAGICVALUE_UDP_SYNC_CLIENT; pachCryptedBuffer[0] = bySemiRandomNotProtocolMarker; memcpy(pachCryptedBuffer + 1, &nRandomKeyPart, 2); RC4Crypt((uchar*)&dwMagicValue, pachCryptedBuffer + 3, 4, &keySendKey); RC4Crypt((uchar*)&byPadLen, pachCryptedBuffer + 7, 1, &keySendKey); for (int j = 0; j < byPadLen; j++){ uint8 byRand = (uint8)rand(); // they actually dont really need to be random, but it doesn't hurts either RC4Crypt((uchar*)&byRand, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1, &keySendKey); } if (bKad){ RC4Crypt((uchar*)&nReceiverVerifyKey, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen, 2, &keySendKey); RC4Crypt((uchar*)&nSenderVerifyKey, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 2, 2, &keySendKey); } RC4Crypt(*ppbyBuf, pachCryptedBuffer + nCryptHeaderLen, nBufLen, &keySendKey); delete[] *ppbyBuf; *ppbyBuf = pachCryptedBuffer; theStats.AddUpDataOverheadCrypt(nCryptedLen - nBufLen); return nCryptedLen; }
int CEncryptedDatagramSocket::DecryptReceivedClient(BYTE* pbyBufIn, int nBufLen, BYTE** ppbyBufOut, uint32 dwIP, uint16* nReceiverVerifyKey, uint16* nSenderVerifyKey) const{ int nResult = nBufLen; *ppbyBufOut = pbyBufIn; if (nResult <= CRYPT_HEADER_WITHOUTPADDING /*|| !thePrefs.IsClientCryptLayerSupported()*/) return nResult; if (nReceiverVerifyKey == NULL || nSenderVerifyKey == NULL){ ASSERT( false ); return nResult; } switch (pbyBufIn[0]){ case OP_EMULEPROT: case OP_KADEMLIAPACKEDPROT: case OP_KADEMLIAHEADER: case OP_UDPRESERVEDPROT1: case OP_UDPRESERVEDPROT2: case OP_PACKEDPROT: return nResult; // no encrypted packet (see description on top) } bool bKad = (pbyBufIn[0] & 0x01) == 0; // check the marker bit if this is a kad or ed2k packet, this is only an indicator since old clients have it set random // might be an encrypted packet, try to decrypt RC4_Key_Struct keyReceiveKey; uint32 dwValue = 0; bool bFlipTry = false; do{ bKad = bFlipTry ? !bKad : bKad; MD5Sum md5; if (bKad){ if (Kademlia::CKademlia::GetPrefs()) { uchar achKeyData[18]; memcpy(achKeyData, Kademlia::CKademlia::GetPrefs()->GetKadID().GetData(), 16); memcpy(achKeyData + 16, pbyBufIn + 1, 2); // random key part sent from remote client md5.Calculate(achKeyData, sizeof(achKeyData)); } } else{ uchar achKeyData[23]; md4cpy(achKeyData, thePrefs.GetUserHash()); achKeyData[20] = MAGICVALUE_UDP; memcpy(achKeyData + 16, &dwIP, 4); memcpy(achKeyData + 21, pbyBufIn + 1, 2); // random key part sent from remote client md5.Calculate(achKeyData, sizeof(achKeyData)); } RC4CreateKey(md5.GetRawHash(), 16, &keyReceiveKey, true); RC4Crypt(pbyBufIn + 3, (uchar*)&dwValue, sizeof(dwValue), &keyReceiveKey); bFlipTry = !bFlipTry; // next round try the other possibility } while (dwValue != MAGICVALUE_UDP_SYNC_CLIENT && bFlipTry); // try to decrypt as ed2k as well as kad packet if needed (max 2 rounds) if (dwValue == MAGICVALUE_UDP_SYNC_CLIENT){ // yup this is an encrypted packet DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from clientIP: %s"), ipstr(dwIP)) ); uint8 byPadLen; RC4Crypt(pbyBufIn + 7, (uchar*)&byPadLen, 1, &keyReceiveKey); nResult -= CRYPT_HEADER_WITHOUTPADDING; if (nResult <= byPadLen){ DebugLogError(_T("Invalid obfuscated UDP packet from clientIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dwIP), byPadLen); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } if (byPadLen > 0) RC4Crypt(NULL, NULL, byPadLen, &keyReceiveKey); nResult -= byPadLen; if (bKad){ if (nResult <= 4){ DebugLogError(_T("Obfuscated Kad packet with mismatching size (verify keys missing) received from clientIP: %s"), ipstr(dwIP)); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk; } // read the verify keys *nReceiverVerifyKey = PeekUInt16(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen); *nSenderVerifyKey = PeekUInt16(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 2); nResult -= 4; } else{ *nReceiverVerifyKey = 0; *nSenderVerifyKey = 0; } *ppbyBufOut = pbyBufIn + (nBufLen - nResult); RC4Crypt((uchar*)*ppbyBufOut, (uchar*)*ppbyBufOut, nResult, &keyReceiveKey); theStats.AddDownDataOverheadCrypt(nBufLen - nResult); return nResult; // done } else{ DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s"), ipstr(dwIP)); return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk } }
void* SomeAwesomeThings(void* Param){ Client* theClient = (Client*)Param; char* message = (char*)malloc(4086); char sendMessage[4086]; char encrypt[4086]; char* receiver; char* tmp; char* ender; char* err; Client* ClientCounter; int msgSize; int usernameSet = 0; int nameLength; int sub_msg_len; int encrypt_len; //RC4 component RC4Container RC4key; int iter1; int iter2; RC4key.iter1 = &iter1; RC4key.iter2 = &iter2; int RC4KeySet = 0; // unsigned char hash_out[SHA_DIGEST_LENGTH + 1]; char hash_string[SHA_DIGEST_LENGTH * 2 + 1]; int iterator; memset(sendMessage, '\0', sizeof(sendMessage)); err = (char*) malloc(130); // if((msgSize = read(theClient->sockfd, message, sizeof(message) - 1)) > 0){ // message[msgSize] = '\0'; // int nameLength = strstr(message, "\r\n.\r\n") - message; // for(msgSize = 0; msgSize < nameLength; msgSize++){ // theClient->Name[msgSize] = message[msgSize]; // } // theClient->Name[nameLength] = '\0'; // printf("%s has connected\n", theClient->Name); // } while((msgSize = read(theClient->sockfd, message, 4086 - 1)) > 0){ message[msgSize] = '\0'; sub_msg_len = 0; while((ender = strstr(message, "\r\n.\r\n")) != NULL){ // *ender = '\0'; sub_msg_len += ender - message + 5; if(sub_msg_len > msgSize) break; // printf("%s\n", message); //Do things here tmp = strstr(message, "\r\n"); *tmp = '\0'; printf("%s\n", message); if(strcmp(message, "Mode: Public") == 0){ tmp = tmp + 2; nameLength = strstr(tmp, "\r\n.\r\n") - tmp + 5; sprintf(sendMessage,"%s\r\nUser: %s\r\n", message, theClient->Name); strncat(sendMessage, tmp, nameLength); for(ClientCounter = head; ClientCounter != NULL; ClientCounter = ClientCounter->Next){ if(ClientCounter == theClient) continue; write(ClientCounter->sockfd, sendMessage, sizeof(sendMessage)); } } else if((strcmp(message, "Mode: Private") == 0) || (strcmp(message, "Mode: InitPriv") == 0) || (strcmp(message, "Mode: AccPriv") == 0) ){ tmp = tmp + 2; tmp = strstr(tmp, " ") + 1; receiver = tmp; tmp = strstr(tmp, "\r\n"); *tmp = '\0'; tmp = tmp + 2; nameLength = strstr(tmp, "\r\n.\r\n") - tmp + 5; sprintf(sendMessage,"%s\r\nUser: %s\r\n", message, theClient->Name); strncat(sendMessage, tmp, nameLength); for(ClientCounter = head; ClientCounter != NULL; ClientCounter = ClientCounter->Next){ if(strcmp(receiver, ClientCounter->Name) == 0){ write(ClientCounter->sockfd, sendMessage, sizeof(sendMessage)); break; } } } else if(strcmp(message, "Mode: GetList") == 0){ sprintf(sendMessage, "Mode: List\r\n"); for(ClientCounter = head; ClientCounter != NULL; ClientCounter = ClientCounter->Next){ if(ClientCounter == theClient)continue; strcat(sendMessage, ClientCounter->Name); strcat(sendMessage, "\r\n"); } strcat(sendMessage, "\r\n.\r\n"); write(theClient->sockfd, sendMessage, sizeof(sendMessage)); } else if(strcmp(message, "Mode: Username") == 0){ tmp = tmp + 2; if(usernameSet == 0){ if(RC4KeySet == 1){ printf("Setting username\n"); nameLength = strstr(tmp, "\r\n.\r\n") - tmp; char* decode; int decode_len = Base64decode(tmp, (unsigned char**)&decode, nameLength); encrypt_len = RC4Crypt(decode_len, (unsigned char*)decode, (unsigned char*)encrypt, &RC4key); free(decode); tmp = strstr(encrypt, "\r\n.,\r\n"); nameLength = tmp - encrypt; *tmp = '\0'; tmp = tmp + 6; if(CheckHashValidation(nameLength, (unsigned char*)encrypt, tmp) == 1){ for(msgSize = 0; msgSize < nameLength; msgSize++){ theClient->Name[msgSize] = *(encrypt + msgSize); } theClient->Name[nameLength] = '\0'; printf("%s\n", theClient->Name); usernameSet++; } } } } else if(strcmp(message, "Mode: GetCA") == 0){ sprintf(sendMessage, "Mode: ServCA\r\n"); strcat(sendMessage, public_key); strcat(sendMessage, "\r\n.\r\n"); write(theClient->sockfd, sendMessage, sizeof(sendMessage)); } else if(strcmp(message, "Mode: SetPubKey") == 0){ tmp = tmp + 2; nameLength = strstr(tmp, "\r\n.\r\n") - tmp; if(RC4KeySet == 1){ char* decoded; int decoded_len = Base64decode(tmp, (unsigned char**)&decoded, nameLength); encrypt_len = RC4Crypt(decoded_len, (unsigned char*)decoded, (unsigned char*)encrypt, &RC4key); free(decoded); encrypt[encrypt_len] = '\0'; tmp = strstr(encrypt, "\r\n.,\r\n"); nameLength = tmp - encrypt; *tmp = '\0'; tmp = tmp + 6; if(CheckHashValidation(nameLength, (unsigned char*)encrypt, tmp) == 1){ for(iterator = 0; iterator < nameLength; iterator++){ *(theClient->public_key + iterator) = *(encrypt + iterator); } *(theClient->public_key + nameLength) = '\0'; } else{ //TODO: Return some error printf("Failed to set public key\n"); sprintf(sendMessage, "Mode: FailPubKey\r\n.\r\n"); write(theClient->sockfd, sendMessage, sizeof(sendMessage)); } } } else if(strcmp(message, "Mode: SetRC4Key") == 0){ if(RC4KeySet == 0){ tmp = tmp + 2; nameLength = strstr(tmp, "\r\n.\r\n") - tmp; char* decoded; int dedoded_len = Base64decode(tmp, (unsigned char**)&decoded, nameLength); if((encrypt_len = private_decrypt((unsigned char*)decoded, dedoded_len, (unsigned char*)private_key, (unsigned char*)encrypt, RSA_PKCS1_OAEP_PADDING)) == -1){ ERR_load_crypto_strings(); ERR_error_string(ERR_get_error(), err); fprintf(stderr, "Error decrypting message: %s\n", err); sprintf(sendMessage, "Mode: FailRC4Key\r\n.\r\n"); write(theClient->sockfd, sendMessage, sizeof(sendMessage)); } else{ tmp = strstr(encrypt, "\r\n.,\r\n"); nameLength = tmp - encrypt; *tmp = '\0'; tmp = tmp + 6; //TODO: Check if hash of encrypt is the same with tmp if(CheckHashValidation(nameLength, (unsigned char*)encrypt, tmp) == 1){ initRC4key(&RC4key, encrypt, nameLength); RC4KeySet = 1; } else{ sprintf(sendMessage, "Mode: FailRC4Key\r\n.\r\n"); write(theClient->sockfd, sendMessage, sizeof(sendMessage)); } } free(decoded); } } else if(strcmp(message, "Mode: GetPubKey") == 0){ tmp = tmp + 2; tmp = strstr(tmp, " ") + 1; receiver = tmp; tmp = strstr(tmp, "\r\n"); *tmp = '\0'; for(ClientCounter = head; ClientCounter != NULL; ClientCounter = ClientCounter->Next){ if(strcmp(receiver, ClientCounter->Name) == 0) break; } if(ClientCounter != NULL){ if(ClientCounter->public_key[0] != '\0' && RC4KeySet == 1){ SHA1((unsigned char*)ClientCounter->public_key, strlen(ClientCounter->public_key), (unsigned char*)hash_out); for(iterator = 0; iterator < SHA_DIGEST_LENGTH; iterator++){ sprintf(&hash_string[iterator * 2], "%02x", (unsigned int)hash_out[iterator]); } sprintf(sendMessage, "%s\r\n.,\r\n%s", ClientCounter->public_key, hash_string); encrypt_len = RC4Crypt(strlen(sendMessage), (unsigned char*)sendMessage, (unsigned char*)encrypt, &RC4key); encrypt[encrypt_len] = '\0'; char* encoded; int encoded_len = Base64encode(encrypt, encrypt_len, &encoded); encoded[encoded_len] = '\0'; sprintf(sendMessage, "Mode: ClientPubKey\r\nUser: %s\r\n%s\r\n.\r\n", ClientCounter->Name, encoded); free(encoded); printf("%s\n", sendMessage); printf("%s\n", ClientCounter->public_key); write(theClient->sockfd, sendMessage, sizeof(sendMessage)); } else{ sprintf(sendMessage, "Mode: FailPubKey\r\nUser: %s\r\n.\r\n", ClientCounter->Name); } } } *ender = '\0'; ender += 5; message = ender; } } printf("%s has been disconnected\n", theClient->Name); if(theClient == head){ head = theClient->Next; if(head != NULL)head->Previous = NULL; else tail = NULL; } else{ theClient->Previous->Next = theClient->Next; if(theClient == tail){ tail = theClient->Previous; } } if(theClient->keypair != NULL) RSA_free(theClient->keypair); free(theClient); return NULL; }
int CEncryptedStreamSocket::Receive(void* lpBuf, int nBufLen, int nFlags){ m_nObfuscationBytesReceived = CAsyncSocketEx::Receive(lpBuf, nBufLen, nFlags); m_bFullReceive = m_nObfuscationBytesReceived == (uint32_t)nBufLen; if(m_nObfuscationBytesReceived == SOCKET_ERROR || m_nObfuscationBytesReceived <= 0){ return m_nObfuscationBytesReceived; } switch (m_StreamCryptState) { case ECS_NONE: // disabled, just pass it through return m_nObfuscationBytesReceived; case ECS_PENDING: case ECS_PENDING_SERVER: ASSERT( false ); DebugLogError(_T("CEncryptedStreamSocket Received data before sending on outgoing connection")); m_StreamCryptState = ECS_NONE; return m_nObfuscationBytesReceived; case ECS_UNKNOWN:{ uint32_t nRead = 1; bool bNormalHeader = false; switch (((uchar*)lpBuf)[0]){ case OP_EDONKEYPROT: case OP_PACKEDPROT: case OP_EMULEPROT: bNormalHeader = true; break; } if (!bNormalHeader){ StartNegotiation(false); const uint32_t nNegRes = Negotiate((uchar*)lpBuf + nRead, m_nObfuscationBytesReceived - nRead); if (nNegRes == (-1)) return 0; nRead += nNegRes; if (nRead != (uint32_t)m_nObfuscationBytesReceived){ // this means we have more data then the current negotiation step required (or there is a bug) and this should never happen // (note: even if it just finished the handshake here, there still can be no data left, since the other client didnt received our response yet) DebugLogError(_T("CEncryptedStreamSocket: Client %s sent more data then expected while negotiating, disconnecting (1)"), DbgGetIPString()); OnError(ERR_ENCRYPTION); } return 0; } else{ // doesn't seems to be encrypted m_StreamCryptState = ECS_NONE; // if we require an encrypted connection, cut the connection here. This shouldn't happen that often // at least with other up-to-date eMule clients because they check for incompability before connecting if possible if (thePrefs.IsClientCryptLayerRequired()){ // TODO: Remove me when i have been solved // Even if the Require option is enabled, we currently have to accept unencrypted connection which are made // for lowid/firewall checks from servers and other from us selected client. Otherwise, this option would // always result in a lowid/firewalled status. This is of course not nice, but we can't avoid this walkarround // untill servers and kad completely support encryption too, which will at least for kad take a bit // only exception is the .ini option ClientCryptLayerRequiredStrict which will even ignore test connections // Update: New server now support encrypted callbacks SOCKADDR_IN sockAddr = {0}; int nSockAddrLen = sizeof(sockAddr); GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (thePrefs.IsClientCryptLayerRequiredStrict() || (!theApp.serverconnect->AwaitingTestFromIP(sockAddr.sin_addr.S_un.S_addr) && !theApp.clientlist->IsKadFirewallCheckIP(sockAddr.sin_addr.S_un.S_addr)) ) { #if defined(_DEBUG) || defined(_BETA) // TODO: Remove after testing AddDebugLogLine(DLP_DEFAULT, false, _T("Rejected incoming connection because Obfuscation was required but not used %s"), DbgGetIPString() ); #endif OnError(ERR_ENCRYPTION_NOTALLOWED); return 0; } else AddDebugLogLine(DLP_DEFAULT, false, _T("Incoming unencrypted firewallcheck connection permitted despite RequireEncryption setting - %s"), DbgGetIPString() ); } return m_nObfuscationBytesReceived; // buffer was unchanged, we can just pass it through } } case ECS_ENCRYPTING: // basic obfuscation enabled and set, so decrypt and pass along RC4Crypt((uchar*)lpBuf, (uchar*)lpBuf, m_nObfuscationBytesReceived, m_pRC4ReceiveKey); return m_nObfuscationBytesReceived; case ECS_NEGOTIATING:{ const uint32_t nRead = Negotiate((uchar*)lpBuf, m_nObfuscationBytesReceived); if (nRead == (-1)) return 0; else if (nRead != (uint32_t)m_nObfuscationBytesReceived && m_StreamCryptState != ECS_ENCRYPTING){ // this means we have more data then the current negotiation step required (or there is a bug) and this should never happen DebugLogError(_T("CEncryptedStreamSocket: Client %s sent more data then expected while negotiating, disconnecting (2)"), DbgGetIPString()); OnError(ERR_ENCRYPTION); return 0; } else if (nRead != (uint32_t)m_nObfuscationBytesReceived && m_StreamCryptState == ECS_ENCRYPTING){ // we finished the handshake and if we this was an outgoing connection it is allowed (but strange and unlikely) that the client sent payload DebugLogWarning(_T("CEncryptedStreamSocket: Client %s has finished the handshake but also sent payload on a outgoing connection"), DbgGetIPString()); memmove(lpBuf, (uchar*)lpBuf + nRead, m_nObfuscationBytesReceived - nRead); return m_nObfuscationBytesReceived - nRead; } else return 0; } default: ASSERT( false ); return m_nObfuscationBytesReceived; } }
void WardenParseCommand0(char *data, int len, int index) { char buf[128]; unsigned char outbuf; *(__int32 *)(modname) = 'udom'; *(__int32 *)(modname + 4) = '\\sel'; for (int i = 0; i != 16; i++) sprintf(modname + 8 + (i << 1), "%02x", (unsigned char)data[i + 1]); modname[40] = '.'; *(int *)(modname + 41) = 'dom'; sprintf(buf, "Warden module %s requested.", modname + 8); AddChat(vbYellow, buf, bot[index]->hWnd_rtfChat); if (currentmodule) { if (cmphash(modhash, data + 1)) { AddChat(vbGreen, "Module already loaded, using that.", bot[index]->hWnd_rtfChat); goto send1; } else { WardenUnloadModule(); AddChat(vbYellow, "New warden module requested, loading that.", bot[index]->hWnd_rtfChat); goto contwprocessing; } } else { contwprocessing: __asm { cld mov esi, data inc esi lea edi, [modhash] movsd movsd movsd movsd lea edi, [moddecryptkey] movsd movsd movsd movsd lea edi, [modsize] movsd } /**(__int32 *)(modhash) = *(__int32 *)(data + 1); *(__int32 *)(modhash + 0x04) = *(__int32 *)(data + 5); *(__int32 *)(modhash + 0x08) = *(__int32 *)(data + 9); *(__int32 *)(modhash + 0x0C) = *(__int32 *)(data + 13); *(__int32 *)(moddecryptkey) = *(__int32 *)(data + 17); *(__int32 *)(moddecryptkey + 0x04) = *(__int32 *)(data + 21); *(__int32 *)(moddecryptkey + 0x08) = *(__int32 *)(data + 25); *(__int32 *)(moddecryptkey + 0x0C) = *(__int32 *)(data + 29); modsize = *(__int32 *)(data + 33); */ if (GetFileAttributes(modname) == INVALID_FILE_ATTRIBUTES) { if (dling) { AddChat(vbYellow, "Module already being downloaded, waiting!", bot[index]->hWnd_rtfChat); goto send1; } AddChat(vbYellow, "Module not found, downloading...", bot[index]->hWnd_rtfChat); rawmodule = (char *)malloc(modsize); moddlprog = 0; outbuf = 0; startedtick = GetTickCount(); dling = 1; } else { WardenPrepareModule(modname); WardenModuleInitalize((LPWMODHEADER)currentmodule); send1: outbuf = 1; } } RC4Crypt(bot[index]->wardenkey_out, &outbuf, 1); InsertByte(outbuf); SendPacket(0x5E, index); }