Upstream tarball 20080414
[amule.git] / src / EncryptedDatagramSocket.cpp
blobee1d86e04eb816470758bc24a081771eb4a74da4
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 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.
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.
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
26 /* Basic Obfusicated Handshake Protocol UDP:
27 see EncryptedStreamSocket.h
29 ****************************** ED2K Packets
31 -Keycreation Client <-> Clinet:
32 - Client A (Outgoing connection):
33 Sendkey: Md5(<UserHashClientB 16><IPClientA 4><MagicValue91 1><RandomKeyPartClientA 2>) 23
34 - Client B (Incomming 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 safe CPU time
38 - Handshake
39 -> The handshake is encrypted - except otherwise noted - by the Keys created above
40 -> Padding is cucrently 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>
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 compromiss, 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
48 ****************************** Server Packets
50 -Keycreation Client <-> Server:
51 - Client A (Outgoing connection client -> server):
52 Sendkey: Md5(<BaseKey 4><MagicValueClientServer 1><RandomKeyPartClientA 2>) 7
53 - Client B (Incomming 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 safe CPU time
57 - Handshake
58 -> The handshake is encrypted - except otherwise noted - by the Keys created above
59 -> Padding is cucrently 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>
62 - Overhead: 8 Bytes per UDP Packet
64 - Security for Basic Obfusication:
65 - Random looking packets, very limited protection against passive eavesdropping single packets
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 compromiss, turning in complete randomness (and nice design) but gaining a lower CPU usage
71 ****************************** KAD Packets
73 -Keycreation Client <-> Client:
74 - Client A (Outgoing connection):
75 Sendkey: Md5(<KadID 16><RandomKeyPartClientA 2>) 18
76 - Client B (Incomming connection):
77 Receivekey: Md5(<KadID 16><RandomKeyPartClientA 2>) 18
78 - Note: The first 1024 Bytes will be _NOT_ discarded for UDP keys to safe CPU time
80 - Handshake
81 -> The handshake is encrypted - except otherwise noted - by the Keys created above
82 -> Padding is cucrently 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>
85 - Overhead: 12 Bytes per UDP Packet
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 compromiss, 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
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"
102 #include <protocol/Protocols.h>
103 #include <common/MD5Sum.h>
105 // random generator
106 #include "CryptoPP_Inc.h" // Needed for Crypto functions
108 #define CRYPT_HEADER_WITHOUTPADDING 8
109 #define MAGICVALUE_UDP 91
110 #define MAGICVALUE_UDP_SYNC_CLIENT 0x395F2EC1
111 #define MAGICVALUE_UDP_SYNC_SERVER 0x13EF24D5
112 #define MAGICVALUE_UDP_SERVERCLIENT 0xA5
113 #define MAGICVALUE_UDP_CLIENTSERVER 0x6B
115 CEncryptedDatagramSocket::CEncryptedDatagramSocket( wxIPaddress &address, wxSocketFlags flags, const CProxyData *proxyData) : CDatagramSocketProxy(address, flags, proxyData)
120 CEncryptedDatagramSocket::~CEncryptedDatagramSocket()
125 int CEncryptedDatagramSocket::DecryptReceivedClient(uint8* pbyBufIn, int nBufLen, uint8** ppbyBufOut, uint32 dwIP, uint16* nReceiverVerifyKey, uint16* nSenderVerifyKey) {
126 int nResult = nBufLen;
127 *ppbyBufOut = pbyBufIn;
129 if (nResult <= CRYPT_HEADER_WITHOUTPADDING /*|| !thePrefs.IsClientCryptLayerSupported()*/)
130 return nResult;
132 if (nReceiverVerifyKey == NULL || nSenderVerifyKey == NULL){
133 wxASSERT( false );
134 return nResult;
137 switch (pbyBufIn[0]){
138 case OP_EMULEPROT:
139 case OP_KADEMLIAPACKEDPROT:
140 case OP_KADEMLIAHEADER:
141 case OP_UDPRESERVEDPROT1:
142 case OP_UDPRESERVEDPROT2:
143 case OP_PACKEDPROT:
144 return nResult; // no encrypted packet (see description on top)
145 default:
149 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
150 // might be an encrypted packet, try to decrypt
152 CRC4EncryptableBuffer receivebuffer;
153 uint32 dwValue = 0;
154 bool bFlipTry = false;
156 bKad = bFlipTry ? !bKad : bKad;
157 MD5Sum md5;
159 if (bKad){
160 if (Kademlia::CKademlia::GetPrefs()) {
161 uint8 achKeyData[18];
162 memcpy(achKeyData, Kademlia::CKademlia::GetPrefs()->GetKadID().GetData(), 16);
163 memcpy(achKeyData + 16, pbyBufIn + 1, 2); // random key part sent from remote client
164 md5.Calculate(achKeyData, sizeof(achKeyData));
166 } else{
167 uint8 achKeyData[23];
168 md4cpy(achKeyData, thePrefs::GetUserHash().GetHash());
169 achKeyData[20] = MAGICVALUE_UDP;
170 PokeUInt32(achKeyData + 16, dwIP);
171 memcpy(achKeyData + 21, pbyBufIn + 1, 2); // random key part sent from remote client
172 md5.Calculate(achKeyData, sizeof(achKeyData));
175 receivebuffer.SetKey(md5, true);
176 receivebuffer.RC4Crypt(pbyBufIn + 3, (uint8*)&dwValue, sizeof(dwValue));
177 ENDIAN_SWAP_I_32(dwValue);
179 bFlipTry = !bFlipTry; // next round try the other possibility
180 } while (dwValue != MAGICVALUE_UDP_SYNC_CLIENT && bFlipTry); // try to decrypt as ed2k as well as kad packet if needed (max 2 rounds)
182 if (dwValue == MAGICVALUE_UDP_SYNC_CLIENT){
183 // Yup this is an encrypted packet
184 //DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from clientIP: %s"), ipstr(dwIP)) );
185 uint8 byPadLen;
187 receivebuffer.RC4Crypt(pbyBufIn + 7, (uint8*)&byPadLen, 1);
188 nResult -= CRYPT_HEADER_WITHOUTPADDING;
190 if (nResult <= byPadLen){
191 //DebugLogError(_T("Invalid obfuscated UDP packet from clientIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dwIP), byPadLen);
192 return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
195 if (byPadLen > 0) {
196 receivebuffer.RC4Crypt(NULL, NULL, byPadLen);
199 nResult -= byPadLen;
201 if (bKad){
202 if (nResult <= 4){
203 //DebugLogError(_T("Obfuscated Kad packet with mismatching size (verify keys missing) received from clientIP: %s"), ipstr(dwIP));
204 return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk;
206 // read the verify keys
207 *nReceiverVerifyKey = PeekUInt16(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen);
208 *nSenderVerifyKey = PeekUInt16(pbyBufIn + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 2);
209 nResult -= 4;
210 } else {
211 *nReceiverVerifyKey = 0;
212 *nSenderVerifyKey = 0;
215 *ppbyBufOut = pbyBufIn + (nBufLen - nResult);
217 receivebuffer.RC4Crypt((uint8*)*ppbyBufOut, (uint8*)*ppbyBufOut, nResult);
218 //theStats.AddDownDataOverheadCrypt(nBufLen - nResult);
219 return nResult; // done
220 } else{
221 //DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from clientIP: %s"), ipstr(dwIP));
222 return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
226 int CEncryptedDatagramSocket::EncryptSendClient(uint8** ppbyBuf, int nBufLen, const uint8* pachClientHashOrKadID, bool bKad, uint16 nReceiverVerifyKey, uint16 nSenderVerifyKey) {
227 wxASSERT( theApp->GetPublicIP() != 0 || bKad );
228 wxASSERT( thePrefs::IsClientCryptLayerSupported() );
230 uint8 byPadLen = 0; // padding disabled for UDP currently
231 const uint32 nCryptHeaderLen = byPadLen + CRYPT_HEADER_WITHOUTPADDING + (bKad ? 4 : 0);
232 uint32 nCryptedLen = nBufLen + nCryptHeaderLen;
233 uint8* pachCryptedBuffer = new uint8[nCryptedLen];
235 uint16 nRandomKeyPart = GetRandomUint16();
236 CRC4EncryptableBuffer sendbuffer;
237 MD5Sum md5;
238 if (bKad) {
239 uint8 achKeyData[18];
240 md4cpy(achKeyData, pachClientHashOrKadID);
241 PokeUInt16(achKeyData+16, nRandomKeyPart);
242 md5.Calculate(achKeyData, sizeof(achKeyData));
243 } else {
244 uint8 achKeyData[23];
245 md4cpy(achKeyData, pachClientHashOrKadID);
246 PokeUInt32(achKeyData+16, theApp->GetPublicIP());
247 PokeUInt16(achKeyData+21, nRandomKeyPart);
248 achKeyData[20] = MAGICVALUE_UDP;
249 md5.Calculate(achKeyData, sizeof(achKeyData));
252 sendbuffer.SetKey(md5, true);
254 // create the semi random byte encryption header
255 uint8 bySemiRandomNotProtocolMarker = 0;
256 int i;
257 for (i = 0; i < 128; i++){
258 bySemiRandomNotProtocolMarker = GetRandomUint8();
259 bySemiRandomNotProtocolMarker = bKad ? (bySemiRandomNotProtocolMarker & 0xFE) : (bySemiRandomNotProtocolMarker | 0x01); // set the ed2k/kad marker bit
261 bool bOk = false;
262 switch (bySemiRandomNotProtocolMarker){ // not allowed values
263 case OP_EMULEPROT:
264 case OP_KADEMLIAPACKEDPROT:
265 case OP_KADEMLIAHEADER:
266 case OP_UDPRESERVEDPROT1:
267 case OP_UDPRESERVEDPROT2:
268 case OP_PACKEDPROT:
269 break;
270 default:
271 bOk = true;
274 if (bOk) {
275 break;
279 if (i >= 128){
280 // either we have _real_ bad luck or the randomgenerator is a bit messed up
281 wxASSERT( false );
282 bySemiRandomNotProtocolMarker = 0x01;
285 pachCryptedBuffer[0] = bySemiRandomNotProtocolMarker;
286 PokeUInt16(pachCryptedBuffer + 1, nRandomKeyPart);
288 uint32 dwMagicValue = ENDIAN_SWAP_32(MAGICVALUE_UDP_SYNC_CLIENT);
289 sendbuffer.RC4Crypt((uint8*)&dwMagicValue, pachCryptedBuffer + 3, 4);
291 sendbuffer.RC4Crypt((uint8*)&byPadLen, pachCryptedBuffer + 7, 1);
293 for (int j = 0; j < byPadLen; j++){
294 uint8 byRand = (uint8)rand(); // they actually dont really need to be random, but it doesn't hurts either
295 sendbuffer.RC4Crypt((uint8*)&byRand, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1);
298 if (bKad){
299 sendbuffer.RC4Crypt((uint8*)&nReceiverVerifyKey, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen, 2);
300 sendbuffer.RC4Crypt((uint8*)&nSenderVerifyKey, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen + 2, 2);
303 sendbuffer.RC4Crypt(*ppbyBuf, pachCryptedBuffer + nCryptHeaderLen, nBufLen);
304 delete[] *ppbyBuf;
305 *ppbyBuf = pachCryptedBuffer;
307 //theStats.AddUpDataOverheadCrypt(nCryptedLen - nBufLen);
308 return nCryptedLen;
311 int CEncryptedDatagramSocket::DecryptReceivedServer(
312 uint8* pbyBufIn,
313 int nBufLen, uint8 **ppbyBufOut,
314 uint32 dwBaseKey,
315 uint32 /*dbgIP*/)
317 int nResult = nBufLen;
318 *ppbyBufOut = pbyBufIn;
320 if (nResult <= CRYPT_HEADER_WITHOUTPADDING || !thePrefs::IsServerCryptLayerUDPEnabled() || dwBaseKey == 0) {
321 return nResult;
324 if(pbyBufIn[0] == OP_EDONKEYPROT) {
325 return nResult; // no encrypted packet (see description on top)
328 // might be an encrypted packet, try to decrypt
329 uint8 achKeyData[7];
330 PokeUInt32(achKeyData, dwBaseKey);
331 achKeyData[4] = MAGICVALUE_UDP_SERVERCLIENT;
332 memcpy(achKeyData + 5, pbyBufIn + 1, 2); // random key part sent from remote server
334 CRC4EncryptableBuffer receivebuffer;
335 MD5Sum md5(achKeyData, sizeof(achKeyData));
336 receivebuffer.SetKey(md5,true);
338 uint32 dwValue;
339 receivebuffer.RC4Crypt(pbyBufIn + 3, (uint8*)&dwValue, sizeof(dwValue));
340 ENDIAN_SWAP_I_32(dwValue);
341 if (dwValue == MAGICVALUE_UDP_SYNC_SERVER){
342 // yup this is an encrypted packet
343 //DEBUG_ONLY( DebugLog(_T("Received obfuscated UDP packet from ServerIP: %s"), ipstr(dbgIP)) );
344 uint8 byPadLen;
345 receivebuffer.RC4Crypt(pbyBufIn + 7, (uint8*)&byPadLen, 1);
346 byPadLen &= 15;
347 nResult -= CRYPT_HEADER_WITHOUTPADDING;
349 if (nResult <= byPadLen){
350 //DebugLogError(_T("Invalid obfuscated UDP packet from ServerIP: %s, Paddingsize (%u) larger than received bytes"), ipstr(dbgIP), byPadLen);
351 return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
354 if (byPadLen > 0) {
355 receivebuffer.RC4Crypt(NULL, NULL, byPadLen);
358 nResult -= byPadLen;
359 *ppbyBufOut = pbyBufIn + (nBufLen - nResult);
360 receivebuffer.RC4Crypt((uint8*)*ppbyBufOut, (uint8*)*ppbyBufOut, nResult);
362 //theStats.AddDownDataOverheadCrypt(nBufLen - nResult);
363 return nResult; // done
364 } else {
365 //DebugLogWarning(_T("Obfuscated packet expected but magicvalue mismatch on UDP packet from ServerIP: %s"), ipstr(dbgIP));
366 return nBufLen; // pass through, let the Receivefunction do the errorhandling on this junk
370 int CEncryptedDatagramSocket::EncryptSendServer(uint8** ppbyBuf, int nBufLen, uint32 dwBaseKey) {
371 wxASSERT( thePrefs::IsServerCryptLayerUDPEnabled() );
372 wxASSERT( dwBaseKey != 0 );
374 uint8 byPadLen = 0; // padding disabled for UDP currently
375 uint32 nCryptedLen = nBufLen + byPadLen + CRYPT_HEADER_WITHOUTPADDING;
376 uint8* pachCryptedBuffer = new uint8[nCryptedLen];
378 uint16 nRandomKeyPart = GetRandomUint16();
380 uint8 achKeyData[7];
381 PokeUInt32(achKeyData, dwBaseKey);
382 achKeyData[4] = MAGICVALUE_UDP_CLIENTSERVER;
383 PokeUInt16(achKeyData + 5, nRandomKeyPart);
384 MD5Sum md5(achKeyData, sizeof(achKeyData));
385 CRC4EncryptableBuffer sendbuffer;
386 sendbuffer.SetKey(md5);
388 // create the semi random byte encryption header
389 uint8 bySemiRandomNotProtocolMarker = 0;
390 int i;
392 for (i = 0; i < 128; i++){
393 bySemiRandomNotProtocolMarker = GetRandomUint8();
394 if (bySemiRandomNotProtocolMarker != OP_EDONKEYPROT) { // not allowed values
395 break;
399 if (i >= 128){
400 // either we have _real_ bad luck or the randomgenerator is a bit messed up
401 wxASSERT( false );
402 bySemiRandomNotProtocolMarker = 0x01;
405 pachCryptedBuffer[0] = bySemiRandomNotProtocolMarker;
406 PokeUInt16(pachCryptedBuffer + 1, nRandomKeyPart);
408 uint32 dwMagicValue = ENDIAN_SWAP_32(MAGICVALUE_UDP_SYNC_SERVER);
409 sendbuffer.RC4Crypt((uint8*)&dwMagicValue, pachCryptedBuffer + 3, 4);
411 sendbuffer.RC4Crypt((uint8*)&byPadLen, pachCryptedBuffer + 7, 1);
413 for (int j = 0; j < byPadLen; j++){
414 uint8 byRand = (uint8)rand(); // they actually dont really need to be random, but it doesn't hurts either
415 sendbuffer.RC4Crypt((uint8*)&byRand, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + j, 1);
417 sendbuffer.RC4Crypt(*ppbyBuf, pachCryptedBuffer + CRYPT_HEADER_WITHOUTPADDING + byPadLen, nBufLen);
418 delete[] *ppbyBuf;
419 *ppbyBuf = pachCryptedBuffer;
421 //theStats.AddUpDataOverheadCrypt(nCryptedLen - nBufLen);
422 return nCryptedLen;