Beispiel #1
0
void CSocks4StateMachine::process_send_command_request(bool entry)
{
	if (entry) {
		// Prepare the request command buffer
		m_buffer[0] = SOCKS4_VERSION;
		switch (m_proxyCommand) {
		case PROXY_CMD_CONNECT:
			m_buffer[1] = SOCKS4_CMD_CONNECT;
			break;
			
		case PROXY_CMD_BIND:
			m_buffer[1] = SOCKS4_CMD_BIND;
			break;
			
		case PROXY_CMD_UDP_ASSOCIATE:
			m_ok = false;
			return;
			break;
		}
		RawPokeUInt16(m_buffer+2, ENDIAN_HTONS(m_peerAddress->Service()));
		// Special processing for SOCKS4a
		switch (m_proxyData.m_proxyType) {
		case PROXY_SOCKS4a:
			PokeUInt32(m_buffer+4, StringIPtoUint32(wxT("0.0.0.1")));
			break;
		case PROXY_SOCKS4:
		default:
			PokeUInt32(m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()));
			break;
		}
		// Common processing for SOCKS4/SOCKS4a
		unsigned int offsetUser = 8;
		unsigned char lenUser = m_proxyData.m_userName.Len();
		memcpy(m_buffer + offsetUser, 
			unicode2char(m_proxyData.m_userName), lenUser);
		m_buffer[offsetUser + lenUser] = 0;
		// Special processing for SOCKS4a
		switch (m_proxyData.m_proxyType) {
		case PROXY_SOCKS4a: {
			unsigned int offsetDomain = offsetUser + lenUser + 1;
			unsigned char lenDomain = m_peerAddress->Hostname().Len();
			memcpy(m_buffer + offsetDomain, 
				unicode2char(m_peerAddress->Hostname()), lenDomain);
			m_buffer[offsetDomain + lenDomain] = 0;
			m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1 + lenDomain + 1;
			break;
		}
		case PROXY_SOCKS4:
		default:
			m_packetLenght = 1 + 1 + 2 + 4 + lenUser + 1;
			break;
		}
		// Send the command packet
		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
	}
}
Beispiel #2
0
void CDownloadQueue::AddToResolve(const CMD4Hash& fileid, const wxString& pszHostname, uint16 port, const wxString& hash, uint8 cryptoptions)
{
	// double checking
	if ( !GetFileByID(fileid) ) {
		return;
	}

	wxMutexLocker lock( m_mutex );
		
	Hostname_Entry entry = { fileid, pszHostname, port, hash, cryptoptions };
	m_toresolve.push_front(entry);

	// Check if there are other DNS lookups on queue
	if (m_toresolve.size() == 1) {
		// Check if it is a simple dot address
		uint32 ip = StringIPtoUint32(pszHostname);

		if (ip) {
			OnHostnameResolved(ip);
		} else {
			CAsyncDNS* dns = new CAsyncDNS(pszHostname, DNS_SOURCE, theApp);

			if ((dns->Create() != wxTHREAD_NO_ERROR) || (dns->Run() != wxTHREAD_NO_ERROR)) {
				dns->Delete();
				m_toresolve.pop_front();
			}
		}
	}
}
Beispiel #3
0
void CSocks5StateMachine::process_send_command_request(bool entry)
{
	if (entry) {
		// Prepare the request command buffer
		m_buffer[0] = SOCKS5_VERSION;
		switch (m_proxyCommand) {
		case PROXY_CMD_CONNECT:
			m_buffer[1] = SOCKS5_CMD_CONNECT;
			break;
			
		case PROXY_CMD_BIND:
			m_buffer[1] = SOCKS5_CMD_BIND;
			break;
			
		case PROXY_CMD_UDP_ASSOCIATE:
			m_buffer[1] = SOCKS5_CMD_UDP_ASSOCIATE;
			break;
		}
		m_buffer[2] = SOCKS5_RSV;
		m_buffer[3] = SOCKS5_ATYP_IPV4_ADDRESS;
		PokeUInt32( m_buffer+4, StringIPtoUint32(m_peerAddress->IPAddress()) );
		RawPokeUInt16( m_buffer+8, ENDIAN_HTONS( m_peerAddress->Service() ) );
		
		// Send the command packet
		m_packetLenght = 10;
		ProxyWrite(*m_proxyClientSocket, m_buffer, m_packetLenght);
	}
}
Beispiel #4
0
wxDatagramSocket &CDatagramSocketProxy::SendTo(
	wxIPaddress &addr, const void* buf, wxUint32 nBytes )
{
	wxMutexLocker lock(m_socketLocker);
	m_lastUDPOperation = UDP_OPERATION_SEND_TO;
	m_lastUDPOverhead = PROXY_UDP_OVERHEAD_IPV4;
	if (m_proxyTCPSocket.GetUseProxy()) {
		if (m_udpSocketOk) {
			m_proxyTCPSocket.GetBuffer()[0] = SOCKS5_RSV;	// Reserved
			m_proxyTCPSocket.GetBuffer()[1] = SOCKS5_RSV;	// Reserved
			m_proxyTCPSocket.GetBuffer()[2] = 0;		// FRAG
			m_proxyTCPSocket.GetBuffer()[3] = SOCKS5_ATYP_IPV4_ADDRESS;
			PokeUInt32( m_proxyTCPSocket.GetBuffer()+4, StringIPtoUint32(addr.IPAddress()));
			RawPokeUInt16( m_proxyTCPSocket.GetBuffer()+8, ENDIAN_HTONS( addr.Service() ) );
			memcpy(m_proxyTCPSocket.GetBuffer() + PROXY_UDP_OVERHEAD_IPV4, buf, nBytes);
			nBytes += PROXY_UDP_OVERHEAD_IPV4;
			wxDatagramSocket::SendTo(
				m_proxyTCPSocket.GetProxyBoundAddress(),
				m_proxyTCPSocket.GetBuffer(), nBytes);
			// Uncomment here to see the buffer contents on console
			// DumpMem(m_proxyTCPSocket.GetBuffer(), nBytes, wxT("SendTo"), 3);
		}
	} else {
		wxDatagramSocket::SendTo(addr, buf, nBytes);
	}
	
	return *this;
}
Beispiel #5
0
void CMuleUDPSocket::OnReceive(int errorCode)
{
	AddDebugLogLineN(logMuleUDP, CFormat(wxT("Got UDP callback for read: Error %i Socket state %i"))
		% errorCode % Ok());

	char buffer[UDP_BUFFER_SIZE];
	amuleIPV4Address addr;
	unsigned length = 0;
	bool error = false;
	int lastError = 0;

	{
		wxMutexLocker lock(m_mutex);

		if (errorCode || (m_socket == NULL) || !m_socket->IsOk()) {
			DestroySocket();
			CreateSocket();

			return;
		}


		length = m_socket->RecvFrom(addr, buffer, UDP_BUFFER_SIZE);
		lastError = m_socket->LastError();
		error = lastError != 0;
	}

	const uint32 ip = StringIPtoUint32(addr.IPAddress());
	const uint16 port = addr.Service();
	if (error) {
		OnReceiveError(lastError, ip, port);
	} else if (length < 2) {
		// 2 bytes (protocol and opcode) is the smallets possible packet.
		AddDebugLogLineN(logMuleUDP, m_name + wxT(": Invalid Packet received"));
	} else if (!ip) {
		// wxFAIL;
		AddLogLineNS(wxT("Unknown ip receiving a UDP packet! Ignoring: '") + addr.IPAddress() + wxT("'"));
	} else if (!port) {
		// wxFAIL;
		AddLogLineNS(wxT("Unknown port receiving a UDP packet! Ignoring"));
	} else if (theApp->clientlist->IsBannedClient(ip)) {
		AddDebugLogLineN(logMuleUDP, m_name + wxT(": Dropped packet from banned IP ") + addr.IPAddress());
	} else {
		AddDebugLogLineN(logMuleUDP, (m_name + wxT(": Packet received ("))
			<< addr.IPAddress() << wxT(":") << port << wxT("): ")
			<< length << wxT("b"));
		OnPacketReceived(ip, port, (byte*)buffer, length);
	}
}
Beispiel #6
0
void CDownloadQueue::OnHostnameResolved(uint32 ip)
{
	wxMutexLocker lock( m_mutex );

	wxASSERT( m_toresolve.size() );
	
	Hostname_Entry resolved = m_toresolve.front();
	m_toresolve.pop_front();

	if ( ip ) {
		CPartFile* file = GetFileByID( resolved.fileid );
		if ( file ) {
			CMemFile sources(1+4+2);
			sources.WriteUInt8(1); // No. Sources
			sources.WriteUInt32(ip);
			sources.WriteUInt16(resolved.port);
			sources.WriteUInt8(resolved.cryptoptions);
			if (resolved.cryptoptions & 0x80) {
				wxASSERT(!resolved.hash.IsEmpty());
				CMD4Hash sourcehash;
				sourcehash.Decode(resolved.hash);
				sources.WriteHash(sourcehash);
			}
			sources.Seek(0,wxFromStart);
			
			file->AddSources(sources, 0, 0, SF_LINK, true);
		}
	}
	
	while (m_toresolve.size()) {
		Hostname_Entry entry = m_toresolve.front();

		// Check if it is a simple dot address
		uint32 tmpIP = StringIPtoUint32(entry.strHostname);

		if (tmpIP) {
			OnHostnameResolved(tmpIP);
		} else {
			CAsyncDNS* dns = new CAsyncDNS(entry.strHostname, DNS_SOURCE, theApp);

			if ((dns->Create() != wxTHREAD_NO_ERROR) || (dns->Run() != wxTHREAD_NO_ERROR)) {
				dns->Delete();
				m_toresolve.pop_front();
			} else {
				break;
			}
		}
	}
}
Beispiel #7
0
void CKadDlg::OnBnClickedBootstrapClient(wxCommandEvent& WXUNUSED(evt))
{
	if (FindWindowById(ID_NODECONNECT)->IsEnabled()) {
		// Ip is reversed since StringIPtoUint32 returns anti-host and kad expects host order
		uint32 ip = StringIPtoUint32(
			dynamic_cast<wxTextCtrl*>(FindWindowById(ID_NODE_IP4))->GetValue() + wxT(".") +
			dynamic_cast<wxTextCtrl*>(FindWindowById(ID_NODE_IP3))->GetValue() + wxT(".") +
			dynamic_cast<wxTextCtrl*>(FindWindowById(ID_NODE_IP2))->GetValue() + wxT(".") +
			dynamic_cast<wxTextCtrl*>(FindWindowById(ID_NODE_IP1))->GetValue() );

		if (ip == 0) {
			wxMessageBox(_("Invalid ip to bootstrap"), _("WARNING"), wxOK | wxICON_EXCLAMATION, this);
		} else {
			unsigned long port;
			if (dynamic_cast<wxTextCtrl*>(FindWindowById(ID_NODE_PORT))->GetValue().ToULong(&port)) {
				theApp->BootstrapKad(ip, port);
			} else {
				wxMessageBox(_("Invalid port to bootstrap"), _("WARNING"), wxOK | wxICON_EXCLAMATION, this);
			}
		}
	} else {
		wxMessageBox(_("Please fill all fields required"), _("Message"), wxOK | wxICON_INFORMATION, this);
	}
}
int CEncryptedStreamSocket::Negotiate(const uint8* pBuffer, uint32 nLen)
{
	uint32_t nRead = 0;
	wxASSERT( m_nReceiveBytesWanted > 0 );

	//DumpMem(pBuffer, nLen, wxT("Negotiate buffer: "));

	try {
		while (m_NegotiatingState != ONS_COMPLETE && m_nReceiveBytesWanted > 0) {
			if (m_nReceiveBytesWanted > 512) {
				wxFAIL;
				return 0;
			}

			const uint32_t nToRead =  std::min(nLen - nRead, m_nReceiveBytesWanted);
			//printf("Reading %i bytes, add from %i position on %i position\n",nToRead, nRead, (int)m_pfiReceiveBuffer.GetPosition());
			//DumpMem(pBuffer + nRead, nToRead, wxT("Recv Buffer: "));
			m_pfiReceiveBuffer.Write(pBuffer + nRead, nToRead);
			nRead += nToRead;
			m_nReceiveBytesWanted -= nToRead;
			if (m_nReceiveBytesWanted > 0)  {
				return nRead;
			}

			if (m_NegotiatingState != ONS_BASIC_CLIENTA_RANDOMPART && m_NegotiatingState != ONS_BASIC_SERVER_DHANSWER) {
				// We have the keys, decrypt
				//printf("We have the keys, so decrypt away on %s\n", (const char*) unicode2char(DbgGetIPString()));
				m_pfiReceiveBuffer.Encrypt();
			}

			m_pfiReceiveBuffer.Seek(0);

			switch (m_NegotiatingState) {
				case ONS_NONE: // would be a bug
					wxFAIL;
					return 0;
				case ONS_BASIC_CLIENTA_RANDOMPART: {
					//printf("We are on ONS_BASIC_CLIENTA_RANDOMPART, create the keys on %s\n", (const char*) unicode2char(DbgGetIPString()));
					// This creates the send/receive keys.

					uint8_t achKeyData[21];
					md4cpy(achKeyData, thePrefs::GetUserHash().GetHash());
					m_pfiReceiveBuffer.Read(achKeyData + 17, 4);

					achKeyData[16] = MAGICVALUE_REQUESTER;

					//DumpMem(achKeyData, sizeof(achKeyData), wxT("ach:"));

					MD5Sum md5(achKeyData, sizeof(achKeyData));
					//DumpMem(md5.GetRawHash(), 16, wxT("Md5:"));
					m_pfiReceiveBuffer.SetKey(md5);

					achKeyData[16] = MAGICVALUE_SERVER;
					md5.Calculate(achKeyData, sizeof(achKeyData));
					m_pfiSendBuffer.SetKey(md5);

					m_NegotiatingState = ONS_BASIC_CLIENTA_MAGICVALUE;
					m_nReceiveBytesWanted = 4;
					break;
				}
				case ONS_BASIC_CLIENTA_MAGICVALUE: {
					// Check the magic value to confirm encryption works.
					//printf("Creating magic value on negotiate on %s\n", (const char*) unicode2char(DbgGetIPString()));

					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
						//printf("Magic value works on %s\n", (const char*) unicode2char(DbgGetIPString()));
						m_NegotiatingState = ONS_BASIC_CLIENTA_METHODTAGSPADLEN;
						m_nReceiveBytesWanted = 3;
					} else {
						//printf("Wrong magic value: 0x%x != 0x%x on %s\n",dwValue, MAGICVALUE_SYNC, (const char*)unicode2char(DbgGetIPString()));
						//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: {
					// Get encryption method and padding.
					// Might fall back to padding process, but the bytes will be ignored.
					//printf("Getting encryption method on negotiation\n");

					m_dbgbyEncryptionSupported = m_pfiReceiveBuffer.ReadUInt8();
					m_dbgbyEncryptionRequested = m_pfiReceiveBuffer.ReadUInt8();

					if (m_dbgbyEncryptionRequested != ENM_OBFUSCATION) {
						//printf("Unsupported encryption method!\n");
//						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 > 0) {
						// No padding
						break;
					}
				}
				case ONS_BASIC_CLIENTA_PADDING: {
					//printf("Negotiating on padding, completing\n");
					// ignore the random bytes, send the response, set status complete
					CMemFile 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);

					amuleIPV4Address address;
					GetPeer(address);
					const uint8_t byPaddingLen = theApp->serverconnect->AwaitingTestFromIP(StringIPtoUint32(address.IPAddress())) ? 16 : (thePrefs::GetCryptTCPPaddingLength() + 1);
					uint8_t byPadding = (uint8_t)(GetRandomUint8() % byPaddingLen);

					fileResponse.WriteUInt8(byPadding);
					for (int i = 0; i < byPadding; i++) {
						fileResponse.WriteUInt8((uint8_t)rand());
					}
					SendNegotiatingData(fileResponse.GetRawBuffer(), (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: {
					//printf("Negotiating on magic value\n");
					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: {
					//printf("Negotiating on client B pad length\n");
					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:
					//printf("Negotiating on client B padding, handshake complete\n");
					// 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: {
					wxASSERT( !m_cryptDHA.IsZero() );
					uint8_t 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 = a_exp_b_mod_c(cryptDHAnswer, m_cryptDHA, cryptDHPrime);

					m_cryptDHA = 0;
					//DEBUG_ONLY( ZeroMemory(aBuffer, sizeof(aBuffer)) );
					wxASSERT( cryptResult.MinEncodedSize() <= PRIMESIZE_BYTES );

					// create the keys
					cryptResult.Encode(aBuffer, PRIMESIZE_BYTES);
					aBuffer[PRIMESIZE_BYTES] = MAGICVALUE_REQUESTER;
					MD5Sum md5(aBuffer, sizeof(aBuffer));
					m_pfiSendBuffer.SetKey(md5);
					aBuffer[PRIMESIZE_BYTES] = MAGICVALUE_SERVER;
					md5.Calculate(aBuffer, sizeof(aBuffer));
					m_pfiReceiveBuffer.SetKey(md5);

					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 > 0) {
						break;
					}
				case ONS_BASIC_SERVER_PADDING: {
					// ignore the random bytes (they are decrypted already), send the response, set status complete
					CMemFile 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);

					// Server callback connection only allows 16 bytes of padding.
					uint8_t byPadding = (uint8_t)(GetRandomUint8() % 16);
					fileResponse.WriteUInt8(byPadding);

					for (int i = 0; i < byPadding; i++) {
						fileResponse.WriteUInt8((uint8_t)rand());
					}

					m_NegotiatingState = ONS_BASIC_SERVER_DELAYEDSENDING;
					SendNegotiatingData(fileResponse.GetRawBuffer(), (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:
					wxFAIL;
			}
			m_pfiReceiveBuffer.ResetData();
		}
		return nRead;
	} catch(...) {
		// can only be caused by a bug in negationhandling, not by the datastream
		//error->Delete();
		//printf("Bug on negotiation?\n");
		wxFAIL;
		OnError(ERR_ENCRYPTION);
		m_pfiReceiveBuffer.ResetData();
		return (-1);
	}
}
int CEncryptedStreamSocket::Read(void* lpBuf, uint32_t nBufLen)
{
	CSocketClientProxy::Read(lpBuf, nBufLen);
	m_nObfusicationBytesReceived = CSocketClientProxy::LastCount();
	m_bFullReceive = m_nObfusicationBytesReceived == (uint32)nBufLen;

	//printf("Read %i bytes on %s, socket %p\n", m_nObfusicationBytesReceived, (const char*) unicode2char(DbgGetIPString()), this);
	
	if (m_nObfusicationBytesReceived == (uint32_t)SOCKET_ERROR || m_nObfusicationBytesReceived <= 0) {
		return m_nObfusicationBytesReceived;
	}
	
	switch (m_StreamCryptState) {
		case ECS_NONE: // disabled, just pass it through
			return m_nObfusicationBytesReceived;
		case ECS_PENDING:
		case ECS_PENDING_SERVER:
			//printf("Received %i bytes before sending?\n", m_nObfusicationBytesReceived);
			wxFAIL;
			//DebugLogError(_T("CEncryptedStreamSocket Received data before sending on outgoing connection"));
			m_StreamCryptState = ECS_NONE;
			return m_nObfusicationBytesReceived;
		case ECS_UNKNOWN: {
			//printf("Receiving encrypted data on ECS_UNKNOWN\n");
			uint32_t nRead = 1;
			bool bNormalHeader = false;
			switch (((uint8_t*)lpBuf)[0]) {
				case OP_EDONKEYPROT:
				case OP_PACKEDPROT:
				case OP_EMULEPROT:
					bNormalHeader = true;
					break;
			}
			
			if (!bNormalHeader) {
				//printf("Not a normal header, negotiating encryption\n");
				StartNegotiation(false);
				const uint32 nNegRes = Negotiate((uint8_t*)lpBuf + nRead, m_nObfusicationBytesReceived - nRead);
				if (nNegRes == (uint32_t)(-1)) {
					return 0;
				}
				nRead += nNegRes;
				if (nRead != (uint32_t)m_nObfusicationBytesReceived) {
					// 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 didn't receive our response yet)
					//DebugLogError(_T("CEncryptedStreamSocket: Client %s sent more data then expected while negotiating, disconnecting (1)"), DbgGetIPString());
					//printf("On error: encryption\n");
					OnError(ERR_ENCRYPTION);
				}
				return 0;
			} else {
				// doesn't seem to be encrypted
				//printf("Encrypted data doesn't seem to be encrypted\n");
				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 workaround
					// until 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
					amuleIPV4Address address;
					GetPeer(address);
					uint32_t ip = StringIPtoUint32(address.IPAddress());
					if (thePrefs::IsClientCryptLayerRequiredStrict() || (!theApp->serverconnect->AwaitingTestFromIP(ip)
						&& !theApp->clientlist->IsKadFirewallCheckIP(ip)) )
					{
						OnError(ERR_ENCRYPTION_NOTALLOWED);
						return 0;
					} else {
						//AddDebugLogLine(DLP_DEFAULT, false, _T("Incoming unencrypted firewallcheck connection permitted despite RequireEncryption setting  - %s"), DbgGetIPString() );
					}
				}
				return m_nObfusicationBytesReceived; // buffer was unchanged, we can just pass it through
			}
		}
		case ECS_ENCRYPTING:
			//printf("Encryption enabled on data receiving, decrypting and passing along\n");
			// basic obfusication enabled and set, so decrypt and pass along
			m_pfiReceiveBuffer.RC4Crypt((uint8_t*)lpBuf, (uint8_t*)lpBuf, m_nObfusicationBytesReceived);
			//DumpMem(lpBuf, m_nObfusicationBytesReceived, wxT("Directly decrypted data:"));
			return m_nObfusicationBytesReceived;
		case ECS_NEGOTIATING:{
			//printf("Negotiating on data receive\n");
			const uint32_t nRead = Negotiate((uint8_t*)lpBuf, m_nObfusicationBytesReceived);
			if (nRead == (uint32_t)(-1)) {
				//printf("-> Encryption read error on negotiation\n");
				return 0;
			} else if (nRead != (uint32_t)m_nObfusicationBytesReceived && m_StreamCryptState != ECS_ENCRYPTING) {
				//printf("-> Too much data, bailing out of negotiation step\n");
				// 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_nObfusicationBytesReceived && m_StreamCryptState == ECS_ENCRYPTING) {
				//printf("-> Handshake negotiation finished\n");
				// 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, (uint8_t*)lpBuf + nRead, m_nObfusicationBytesReceived - nRead);
				return m_nObfusicationBytesReceived - nRead;
			} else {
				//printf("-> Negotiation went probably ok\n");
				return 0;
			}
		}
		default:
			wxFAIL;
			return m_nObfusicationBytesReceived;
	}
}