1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
24//
25
26/* Basic Obfuscated Handshake Protocol UDP:
27	see EncryptedStreamSocket.h
28
29****************************** ED2K Packets
30
31- Keycreation Client <-> Client:
32	- Client A (Outgoing connection):
33		Sendkey: Md5(<UserHashClientB 16><IPClientA 4><MagicValue91 1><RandomKeyPartClientA 2>)  23
34	- Client B (Incoming connection):
35		Receivekey: Md5(<UserHashClientB 16><IPClientA 4><MagicValue91 1><RandomKeyPartClientA 2>)  23
36	- Note: The first 1024 Bytes will be _NOT_ discarded for UDP keys to save CPU time
37
38	- Handshake
39		-> The handshake is encrypted - except otherwise noted - by the Keys created above
40		-> Padding is currently not used for UDP meaning that PaddingLen will be 0, using PaddingLens up to 16 Bytes is acceptable however
41		Client A: <SemiRandomNotProtocolMarker 7 Bits[Unencrypted]><ED2K Marker 1Bit = 1><RandomKeyPart 2[Unencrypted]><MagicValue 4><PaddingLen 1><RandomBytes PaddingLen%16>
42
43	- Additional Comments:
44		- For obvious reasons the UDP handshake is actually no handshake. If a different Encryption method (or better a different Key) is to be used this has to be negotiated in a TCP connection
45		- SemiRandomNotProtocolMarker is a Byte which has a value unequal any Protocol header byte. This is a compromise, turning in complete randomness (and nice design) but gaining a lower CPU usage
46		- Kad/Ed2k Marker are only indicators, which possibility could be tried first, and should not be trusted
47
48****************************** Server Packets
49
50- Keycreation Client <-> Server:
51	- Client A (Outgoing connection client -> server):
52		Sendkey: Md5(<BaseKey 4><MagicValueClientServer 1><RandomKeyPartClientA 2>)  7
53	- Client B (Incoming connection):
54		Receivekey: Md5(<BaseKey 4><MagicValueServerClient 1><RandomKeyPartClientA 2>)  7
55	- Note: The first 1024 Bytes will be _NOT_ discarded for UDP keys to save CPU time
56
57	- Handshake
58		-> The handshake is encrypted - except otherwise noted - by the Keys created above
59		-> Padding is currently not used for UDP meaning that PaddingLen will be 0, using PaddingLens up to 16 Bytes is acceptable however
60		Client A: <SemiRandomNotProtocolMarker 1[Unencrypted]><RandomKeyPart 2[Unencrypted]><MagicValue 4><PaddingLen 1><RandomBytes PaddingLen%16>
61
62	- Overhead: 8 Bytes per UDP Packet
63
64	- Security for Basic Obfuscation:
65		- Random looking packets, very limited protection against passive eavesdropping single packets
66
67	- Additional Comments:
68		- For obvious reasons the UDP handshake is actually no handshake. If a different Encryption method (or better a different Key) is to be used this has to be negotiated in a TCP connection
69		- SemiRandomNotProtocolMarker is a Byte which has a value unequal any Protocol header byte. This is a compromise, turning in complete randomness (and nice design) but gaining a lower CPU usage
70
71****************************** KAD Packets
72
73- Keycreation Client <-> Client:
74	- Client A (Outgoing connection):
75		Sendkey: Md5(<KadID 16><RandomKeyPartClientA 2>)  18
76	- Client B (Incoming connection):
77		Receivekey: Md5(<KadID 16><RandomKeyPartClientA 2>)  18
78	- Note: The first 1024 Bytes will be _NOT_ discarded for UDP keys to save CPU time
79
80	- Handshake
81		-> The handshake is encrypted - except otherwise noted - by the Keys created above
82		-> Padding is currently not used for UDP meaning that PaddingLen will be 0, using PaddingLens up to 16 Bytes is acceptable however
83		Client A: <SemiRandomNotProtocolMarker 7 Bits[Unencrypted]><Kad Marker 1Bit = 0><RandomKeyPart 2[Unencrypted]><MagicValue 4><PaddingLen 1><RandomBytes PaddingLen%16><ReceiverVerifyKey 2><SenderVerifyKey 2>
84
85	- Overhead: 12 Bytes per UDP Packet
86
87	- Additional Comments:
88		- For obvious reasons the UDP handshake is actually no handshake. If a different Encryption method (or better a different Key) is to be used this has to be negotiated in a TCP connection
89		- SemiRandomNotProtocolMarker is a Byte which has a value unequal any Protocol header byte. This is a compromise, turning in complete randomness (and nice design) but gaining a lower CPU usage
90		- Kad/Ed2k Marker are only indicators, which possibility could be tried first, and should not be trusted
91*/
92
93#include "EncryptedDatagramSocket.h"
94#include "amule.h"
95#include "Logger.h"
96#include "Preferences.h"
97#include "RC4Encrypt.h"
98#include "./kademlia/kademlia/Prefs.h"
99#include "./kademlia/kademlia/Kademlia.h"
100#include "RandomFunctions.h"
101#include "Statistics.h"
102
103#include <protocol/Protocols.h>
104#include <common/MD5Sum.h>
105
106// random generator
107#include "CryptoPP_Inc.h"	// Needed for Crypto functions
108
109#define CRYPT_HEADER_WITHOUTPADDING		    8
110#define	MAGICVALUE_UDP						91
111#define MAGICVALUE_UDP_SYNC_CLIENT			0x395F2EC1
112#define MAGICVALUE_UDP_SYNC_SERVER			0x13EF24D5
113#define	MAGICVALUE_UDP_SERVERCLIENT			0xA5
114#define	MAGICVALUE_UDP_CLIENTSERVER			0x6B
115
116CEncryptedDatagramSocket::CEncryptedDatagramSocket(wxIPaddress &address, wxSocketFlags flags,	const CProxyData *proxyData)
117	: CDatagramSocketProxy(address, flags, proxyData)
118{}
119
120CEncryptedDatagramSocket::~CEncryptedDatagramSocket()
121{}
122
123int CEncryptedDatagramSocket::DecryptReceivedClient(uint8_t *bufIn, int bufLen, uint8_t **bufOut, uint32_t ip, uint32_t *receiverVerifyKey, uint32_t *senderVerifyKey)
124{
125	int result = bufLen;
126	*bufOut = bufIn;
127
128	if (receiverVerifyKey == NULL || senderVerifyKey == NULL) {
129		wxFAIL;
130		return result;
131	}
132
133	*receiverVerifyKey = 0;
134	*senderVerifyKey = 0;
135
136	if (result <= CRYPT_HEADER_WITHOUTPADDING /*|| !thePrefs.IsClientCryptLayerSupported()*/) {
137		return result;
138	}
139
140	switch (bufIn[0]) {
141		case OP_EMULEPROT:
142		case OP_KADEMLIAPACKEDPROT:
143		case OP_KADEMLIAHEADER:
144		case OP_UDPRESERVEDPROT1:
145		case OP_UDPRESERVEDPROT2:
146		case OP_PACKEDPROT:
147			return result; // no encrypted packet (see description on top)
148		default:
149			;
150	}
151
152	// might be an encrypted packet, try to decrypt
153	CRC4EncryptableBuffer receivebuffer;
154	uint32_t value = 0;
155	// 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
156	// see the header for marker bits explanation
157	uint8_t currentTry = ((bufIn[0] & 0x03) == 3) ? 1 : (bufIn[0] & 0x03);
158	uint8_t tries;
159	if (Kademlia::CKademlia::GetPrefs() == NULL) {
160		// if kad never run, no point in checking anything except for ed2k encryption
161		tries = 1;
162		currentTry = 1;
163	} else {
164		tries = 3;
165	}
166	bool kad = false;
167	do {
168		receivebuffer.FullReset();
169		tries--;
170		MD5Sum md5;
171
172		if (currentTry == 0) {
173			// kad packet with NodeID as key
174			kad = true;
175			if (Kademlia::CKademlia::GetPrefs()) {
176				uint8_t keyData[18];
177				Kademlia::CKademlia::GetPrefs()->GetKadID().StoreCryptValue((uint8_t *)&keyData);
178				memcpy(keyData + 16, bufIn + 1, 2); // random key part sent from remote client
179				md5.Calculate(keyData, sizeof(keyData));
180			}
181		} else if (currentTry == 1) {
182			// ed2k packet
183			kad = false;
184			uint8_t keyData[23];
185			md4cpy(keyData, thePrefs::GetUserHash().GetHash());
186			keyData[20] = MAGICVALUE_UDP;
187			PokeUInt32(keyData + 16, ip);
188			memcpy(keyData + 21, bufIn + 1, 2); // random key part sent from remote client
189			md5.Calculate(keyData, sizeof(keyData));
190		} else if (currentTry == 2) {
191			// kad packet with ReceiverKey as key
192			kad = true;
193			if (Kademlia::CKademlia::GetPrefs()) {
194				uint8_t keyData[6];
195				PokeUInt32(keyData, Kademlia::CPrefs::GetUDPVerifyKey(ip));
196				memcpy(keyData + 4, bufIn + 1, 2); // random key part sent from remote client
197				md5.Calculate(keyData, sizeof(keyData));
198			}
199		} else {
200			wxFAIL;
201		}
202
203		receivebuffer.SetKey(md5, true);
204		receivebuffer.RC4Crypt(bufIn + 3, (uint8_t*)&value, sizeof(value));
205		ENDIAN_SWAP_I_32(value);
206
207		currentTry = (currentTry + 1) % 3;
208	} while (value != MAGICVALUE_UDP_SYNC_CLIENT && tries > 0); // try to decrypt as ed2k as well as kad packet if needed (max 3 rounds)
209
210	if (value == MAGICVALUE_UDP_SYNC_CLIENT) {
211		// yup this is an encrypted packet
212// 		// debugoutput notices
213// 		// the following cases are "allowed" but shouldn't happen given that there is only our implementation yet
214// 		if (bKad && (pbyBufIn[0] & 0x01) != 0)
215// 			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, ed2k bit)"), ipstr(dwIP));
216// 		else if (bKad && !bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) != 0)
217// 			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, nodeid key, recvkey bit)"), ipstr(dwIP));
218// 		else if (bKad && bKadRecvKeyUsed && (pbyBufIn[0] & 0x02) == 0)
219// 			DebugLog(_T("Received obfuscated UDP packet from clientIP: %s with wrong key marker bits (kad packet, recvkey key, nodeid bit)"), ipstr(dwIP));
220
221		uint8_t padLen;
222		receivebuffer.RC4Crypt(bufIn + 7, (uint8_t*)&padLen, 1);
223		result -= CRYPT_HEADER_WITHOUTPADDING;
224
225		if (result <= padLen) {
226			//DebugLogError(_T("Invalid obfuscated UDP packet from clientIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dwIP), byPadLen);
227			return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk
228		}
229
230		if (padLen > 0) {
231			receivebuffer.RC4Crypt(NULL, NULL, padLen);
232		}
233
234		result -= padLen;
235
236		if (kad) {
237			if (result <= 8) {
238				//DebugLogError(_T("Obfuscated Kad packet with mismatching size (verify keys missing) received from clientIP: %s"), ipstr(dwIP));
239				return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk;
240			}
241			// read the verify keys
242			receivebuffer.RC4Crypt(bufIn + CRYPT_HEADER_WITHOUTPADDING + padLen, (uint8_t*)receiverVerifyKey, 4);
243			receivebuffer.RC4Crypt(bufIn + CRYPT_HEADER_WITHOUTPADDING + padLen + 4, (uint8_t*)senderVerifyKey, 4);
244			ENDIAN_SWAP_I_32(*receiverVerifyKey);
245			ENDIAN_SWAP_I_32(*senderVerifyKey);
246			result -= 8;
247		}
248
249		*bufOut = bufIn + (bufLen - result);
250
251		receivebuffer.RC4Crypt((uint8_t*)*bufOut, (uint8_t*)*bufOut, result);
252		theStats::AddDownOverheadCrypt(bufLen - result);
253		return result; // done
254	} else {
255		//DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s"), ipstr(dwIP));
256		return bufLen; // pass through, let the Receivefunction do the errorhandling on this junk
257	}
258}
259
260// Encrypt packet. Key used:
261// clientHashOrKadID != NULL					-> clientHashOrKadID
262// clientHashOrKadID == NULL && kad && receiverVerifyKey != 0	-> receiverVerifyKey
263// else								-> ASSERT
264int CEncryptedDatagramSocket::EncryptSendClient(uint8_t **buf, int bufLen, const uint8_t *clientHashOrKadID, bool kad, uint32_t receiverVerifyKey, uint32_t senderVerifyKey)
265{
266	wxASSERT(theApp->GetPublicIP() != 0 || kad);
267	wxASSERT(thePrefs::IsClientCryptLayerSupported());
268	wxASSERT(clientHashOrKadID != NULL || receiverVerifyKey != 0);
269	wxASSERT((receiverVerifyKey == 0 && senderVerifyKey == 0) || kad);
270
271	uint8_t padLen = 0;			// padding disabled for UDP currently
272	const uint32_t cryptHeaderLen = padLen + CRYPT_HEADER_WITHOUTPADDING + (kad ? 8 : 0);
273	uint32_t cryptedLen = bufLen + cryptHeaderLen;
274	uint8_t *cryptedBuffer = new uint8_t[cryptedLen];
275	bool kadRecvKeyUsed = false;
276
277	uint16_t randomKeyPart = GetRandomUint16();
278	CRC4EncryptableBuffer sendbuffer;
279	MD5Sum md5;
280	if (kad) {
281		if ((clientHashOrKadID == NULL || CMD4Hash(clientHashOrKadID).IsEmpty()) && receiverVerifyKey != 0) {
282			kadRecvKeyUsed = true;
283			uint8_t keyData[6];
284			PokeUInt32(keyData, receiverVerifyKey);
285			PokeUInt16(keyData+4, randomKeyPart);
286			md5.Calculate(keyData, sizeof(keyData));
287			//DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by ReceiverKey (%u)"), nReceiverVerifyKey) );
288		}
289		else if (clientHashOrKadID != NULL && !CMD4Hash(clientHashOrKadID).IsEmpty()) {
290			uint8_t keyData[18];
291			md4cpy(keyData, clientHashOrKadID);
292			PokeUInt16(keyData+16, randomKeyPart);
293			md5.Calculate(keyData, sizeof(keyData));
294			//DEBUG_ONLY( DebugLog(_T("Creating obfuscated Kad packet encrypted by Hash/NodeID %s"), md4str(pachClientHashOrKadID)) );
295		}
296		else {
297			wxFAIL;
298			return bufLen;
299		}
300	} else {
301		uint8_t keyData[23];
302		md4cpy(keyData, clientHashOrKadID);
303		PokeUInt32(keyData+16, theApp->GetPublicIP());
304		PokeUInt16(keyData+21, randomKeyPart);
305		keyData[20] = MAGICVALUE_UDP;
306		md5.Calculate(keyData, sizeof(keyData));
307	}
308
309	sendbuffer.SetKey(md5, true);
310
311	// create the semi random byte encryption header
312	uint8_t semiRandomNotProtocolMarker = 0;
313	int i;
314	for (i = 0; i < 128; i++) {
315		semiRandomNotProtocolMarker = GetRandomUint8();
316		semiRandomNotProtocolMarker = kad ? (semiRandomNotProtocolMarker & 0xFE) : (semiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit
317		if (kad) {
318			// set the ed2k/kad and nodeid/recvkey markerbit
319			semiRandomNotProtocolMarker = kadRecvKeyUsed ? ((semiRandomNotProtocolMarker & 0xFE) | 0x02) : (semiRandomNotProtocolMarker & 0xFC);
320		} else {
321			// set the ed2k/kad marker bit
322			semiRandomNotProtocolMarker = (semiRandomNotProtocolMarker | 0x01);
323		}
324
325		bool bOk = false;
326		switch (semiRandomNotProtocolMarker) { // not allowed values
327			case OP_EMULEPROT:
328			case OP_KADEMLIAPACKEDPROT:
329			case OP_KADEMLIAHEADER:
330			case OP_UDPRESERVEDPROT1:
331			case OP_UDPRESERVEDPROT2:
332			case OP_PACKEDPROT:
333				break;
334			default:
335				bOk = true;
336		}
337
338		if (bOk) {
339			break;
340		}
341	}
342
343	if (i >= 128) {
344		// either we have _real_ bad luck or the randomgenerator is a bit messed up
345		wxFAIL;
346		semiRandomNotProtocolMarker = 0x01;
347	}
348
349	cryptedBuffer[0] = semiRandomNotProtocolMarker;
350	PokeUInt16(cryptedBuffer + 1, randomKeyPart);
351
352	uint32_t magicValue = ENDIAN_SWAP_32(MAGICVALUE_UDP_SYNC_CLIENT);
353	sendbuffer.RC4Crypt((uint8_t*)&magicValue, cryptedBuffer + 3, 4);
354	sendbuffer.RC4Crypt((uint8_t*)&padLen, cryptedBuffer + 7, 1);
355
356	for (int j = 0; j < padLen; j++) {
357		uint8_t byRand = (uint8_t)rand();	// they actually don't really need to be random, but it doesn't hurt either
358		sendbuffer.RC4Crypt((uint8_t*)&byRand, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1);
359	}
360
361	if (kad) {
362		ENDIAN_SWAP_I_32(receiverVerifyKey);
363		ENDIAN_SWAP_I_32(senderVerifyKey);
364		sendbuffer.RC4Crypt((uint8_t*)&receiverVerifyKey, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + padLen, 4);
365		sendbuffer.RC4Crypt((uint8_t*)&senderVerifyKey, cryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + padLen + 4, 4);
366	}
367
368	sendbuffer.RC4Crypt(*buf, cryptedBuffer + cryptHeaderLen, bufLen);
369	delete [] *buf;
370	*buf = cryptedBuffer;
371
372	theStats::AddUpOverheadCrypt(cryptedLen - bufLen);
373	return cryptedLen;
374}
375
376int CEncryptedDatagramSocket::DecryptReceivedServer(uint8_t* pbyBufIn, int nBufLen, uint8_t **ppbyBufOut, uint32_t dwBaseKey, uint32_t /*dbgIP*/)
377{
378	int nResult = nBufLen;
379	*ppbyBufOut = pbyBufIn;
380
381	if (nResult <= CRYPT_HEADER_WITHOUTPADDING || !thePrefs::IsServerCryptLayerUDPEnabled() || dwBaseKey == 0) {
382		return nResult;
383	}
384
385	if(pbyBufIn[0] == OP_EDONKEYPROT) {
386		return nResult; // no encrypted packet (see description on top)
387	}
388
389	// might be an encrypted packet, try to decrypt
390	uint8_t achKeyData[7];
391	PokeUInt32(achKeyData, dwBaseKey);
392	achKeyData[4] = MAGICVALUE_UDP_SERVERCLIENT;
393	memcpy(achKeyData + 5, pbyBufIn + 1, 2); // random key part sent from remote server
394
395	CRC4EncryptableBuffer receivebuffer;
396	MD5Sum md5(achKeyData, sizeof(achKeyData));
397	receivebuffer.SetKey(md5,true);
398
399	uint32_t dwValue;
400	receivebuffer.RC4Crypt(pbyBufIn + 3, (uint8_t*)&dwValue, sizeof(dwValue));
401	ENDIAN_SWAP_I_32(dwValue);
402	if (dwValue == MAGICVALUE_UDP_SYNC_SERVER) {
403		// yup this is an encrypted packet
404		//DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from ServerIP: %s"), ipstr(dbgIP)) );
405		uint8_t byPadLen;
406		receivebuffer.RC4Crypt(pbyBufIn + 7, (uint8_t*)&byPadLen, 1);
407		byPadLen &= 15;
408		nResult -= CRYPT_HEADER_WITHOUTPADDING;
409
410		if (nResult <= byPadLen) {
411			//DebugLogError(_T("Invalid obfuscated UDP packet from ServerIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dbgIP), byPadLen);
412			return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
413		}
414
415		if (byPadLen > 0) {
416			receivebuffer.RC4Crypt(NULL, NULL, byPadLen);
417		}
418
419		nResult -= byPadLen;
420		*ppbyBufOut = pbyBufIn + (nBufLen - nResult);
421		receivebuffer.RC4Crypt((uint8_t*)*ppbyBufOut, (uint8_t*)*ppbyBufOut, nResult);
422
423		theStats::AddDownOverheadCrypt(nBufLen - nResult);
424		return nResult; // done
425	} else {
426		//DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from ServerIP: %s"), ipstr(dbgIP));
427		return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
428	}
429}
430
431int CEncryptedDatagramSocket::EncryptSendServer(uint8_t** ppbyBuf, int nBufLen, uint32_t dwBaseKey)
432{
433	wxASSERT( thePrefs::IsServerCryptLayerUDPEnabled() );
434	wxASSERT( dwBaseKey != 0 );
435
436	uint16_t nRandomKeyPart = GetRandomUint16();
437
438	uint8_t achKeyData[7];
439	PokeUInt32(achKeyData, dwBaseKey);
440	achKeyData[4] = MAGICVALUE_UDP_CLIENTSERVER;
441	PokeUInt16(achKeyData + 5, nRandomKeyPart);
442	MD5Sum md5(achKeyData, sizeof(achKeyData));
443	CRC4EncryptableBuffer sendbuffer;
444	sendbuffer.SetKey(md5, true);
445
446	// create the semi random byte encryption header
447	uint8_t bySemiRandomNotProtocolMarker = 0;
448	int i;
449
450	for (i = 0; i < 128; i++) {
451		bySemiRandomNotProtocolMarker = GetRandomUint8();
452		if (bySemiRandomNotProtocolMarker != OP_EDONKEYPROT) { // not allowed values
453			break;
454		}
455	}
456
457	if (i >= 128) {
458		// either we have _real_ bad luck or the randomgenerator is a bit messed up
459		wxFAIL;
460		bySemiRandomNotProtocolMarker = 0x01;
461	}
462
463	uint8_t byPadLen = 0;			// padding disabled for UDP currently
464	uint32_t nCryptedLen = nBufLen + byPadLen + CRYPT_HEADER_WITHOUTPADDING;
465	uint8_t* pachCryptedBuffer = new uint8_t[nCryptedLen];
466
467	pachCryptedBuffer[0] = bySemiRandomNotProtocolMarker;
468	PokeUInt16(pachCryptedBuffer + 1, nRandomKeyPart);
469
470	uint32_t dwMagicValue = ENDIAN_SWAP_32(MAGICVALUE_UDP_SYNC_SERVER);
471	sendbuffer.RC4Crypt((uint8_t*)&dwMagicValue, pachCryptedBuffer + 3, 4);
472
473	sendbuffer.RC4Crypt((uint8_t*)&byPadLen, pachCryptedBuffer + 7, 1);
474
475	for (int j = 0; j < byPadLen; j++){
476		uint8_t byRand = (uint8_t)rand();	// they actually don't really need to be random, but it doesn't hurt either
477		sendbuffer.RC4Crypt((uint8_t*)&byRand, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1);
478	}
479	sendbuffer.RC4Crypt(*ppbyBuf, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen, nBufLen);
480	delete[] *ppbyBuf;
481	*ppbyBuf = pachCryptedBuffer;
482
483	theStats::AddUpOverheadCrypt(nCryptedLen - nBufLen);
484	return nCryptedLen;
485}
486