EDKObfuscation

From MLDonkey
Jump to: navigation, search

Contents

Where to look at

in the eMule 0.48a sources

eMule 0.48a seems to have implemented the bigger part of the logic in EncryptedStreamSocket.h and EncryptedStreamSocket.cpp. The encryption is AFAIK implemented as a frontend to CAsyncSocketEx, supposedly because the latter is used for communication and extending it would make it compatible with existing code. An implementation in mldonkey could use the same techique. It could wrap the encryption code just around the existing "connections" infrastructure. It also makes understanding the algorithm comparably easy, since all we need to look at sits in EncryptedStreamSocket.cpp (well and EncryptedDatagramSocket respectively).

The file EncryptedStreamSocket.cpp also contains a brief introduction to protocol applied. The big encryption and decryption parts sit in the Receive() and the Send() methods. That's also where the larger part of the state machine inside those classes is handled. The encryption negotiation sits in the Negotiate() method. For the encryption itself RC4 seems to be used. The initial author of this section will provide a few UML graphs of his findings soon as well (in other words: stay tuned).

The eMule encryption state machine for stream sockets

Overview

The encryption state machine is implemented as an extension to sockets eMule uses for up- and downloading as class CEncryptedStreamSocket in EncryptedStreamSocket.cpp. There are three possible connection types:

As a result we find three possible flows through that state machine: CEncryptedStreamSocket-Statemachine.png

The protocol state machine for server sockets

For server connections the initial keys are exchange via Diffie-Hellman key exchange. That type of key exchange ensures that only the exchanging peers will be able to read the traffic between each other and is widely used.

Transition 15: Diffie-Hellman exchange 1st step

This is the first step in establishing a encrypted connection to an eDonkey server. In this transition our local key is calculated and send to the server using a DH exchange. Prior to sending any data the following numbers are calculated:

In the Wikipedia page example g = 2

Data transmitted
Length Content
1 Byte SemiRandomNotProtocolMarker (see below)
96 Bytes e
1 Byte Padding length
n Byte Padding

Transition 16: Diffie-Hellman exchange 2nd step

In the 2nd step, we receive the server exchange and calculate all the keys (see below).

Data read
Length Content
96 Bytes d

Now with the above received data the keys are calculated as follows:

Transition 17: Verification of the key exchange succeeded

From the 3rds step on, all the communication is sent in a RC4 encrypted stream. In the 3rd step, we verify that the server has the correct idea about what our keys are. It will have got a 4 byte value from the server that should equal to MAGICVALUE_SYNC.

Data read
Length Content
4 Byte dwValue

if dwValue will be decrypted and compared with MAGICVALUE_SYNC. If they're equal the key is known to the server, as it could encode it correctly.

Transition 18: Check for the encryption method succeeded

In the 4th step we check that the encryption method presented by the server is supported here. eMule 0.48a only supports ENM_OBFUSCATION.

Data read
Length Content
1 Byte Encryption supported
1 Byte Encryption requested
1 Byte Padding length

Transition 19: The padding has been read from the socket

The 5th step of server encryption establishment is about reading the padding data from the socket and sending the server a confirmation that we have the right idea about its key. For that reason we send MAGICVALUE_SYNC. Further we select ENM_OBFUSCATION as the encryption method and send some garbage as padding.

Data read
Length Content
n Byte Padding
Data written
Length Content
4 Byte MAGICVALUE_SYNC
1 Byte ENM_OBFUSCATION ( the selected encryption method )
1 Byte padding length
n Byte padding

Transition 20: Logging into the server

Here we send our normal eDonkey login over the encrypted connection and if we did everything else right we'll receive a proper response from it.

SemiRandomNotProtocolMarker

The SemiRandomNotProtocolMarker used above is to make sure that the protocol is not misunderstood as an unencrypted protocol. For that reason the first byte of the stream cannot be OP_EDONKEYPROT, OP_PACKEDPROT or OP_EMULEPROT. eMule will try up to 128 times to find a random number that is not equal to these three. So each number unequal to these three values is considered a protocol marker for an encrypted stream.

The protocol state machine for outgoing client sockets

Inter-client key generation

Unlike in the server handshake, where the intial key is exchange with Diffie-Hellman, the keys for the clients are generated based on their client hash.

Transition 11: Initiating an outgoing connection

Transition 11 happens when after connecting the socket, the encrypted handshake is initiated.

The inter-client key generation algorithm is performed:

Buffer for client key exchange
Length Content
16 Bytes Client MD4 hash
1 Byte Either MAGICVALUE_REQUESTER
4 Byte Random key part
Data transmitted
Length Content
1 Byte SemiRandomNotProtocolMarker
4 Byte random part of the initiator
4 Byte MAGICVALUE_SYNC
1 Byte ENM_OBFUSCATION (our supported encryption protocol)
1 Byte ENM_OBFUSCATION (our preferred encryption protocol)
1 Byte padding length
n Byte padding

Since the initiator already knows the client MD4 hash of the outgoing connection, it can encrypt the traffic without any previous handshake. The encryption starts after the random part of the initiator and thus with byte 5.

Transition 12: Verification of the key exchange succeeded

The received dwValue has been compared with MAGICVALUE_SYNC and was identical.

Data received
Length Content
4 Byte dwValue

Transition 13: The selected encryption method has been verified to be supported.

Data received
Length Content
1 Byte EncryptionMethodSet
1 Byte Padding length

Transition 14: The padding has been received

Data received
Length Content
n Byte Padding

The protocol state machine for incoming client connections

Transition 6: The random part has been received

Data received
Length Content
1 Byte SemiRandomNotProtocolMarker
4 Byte random part of the initiator

This is the companion of transition 11.

Transition 7: Our random-part has been sent to the initiator

Prior to sending the random-part the inter-client key generation takes place:

Incoming connection key exchange buffer
Length Content
16 Byte My MD4 client hash
1 Byte MAGICVALUE_REQUESTER
4 Byte received random part from initiator
Data sent
Length Content
4 Bytes Random part

Transition 8: It has been verified that the key exchange succeeded

Data received
Length Content
4 Bytes dwValue

dwValue has been equal to MAGICVALUE_SYNC and thus had been encrypted correctly by the peer.

Transition 9: List of supported protocols received and supported

Data received
Length Content
1 Byte EncryptionSupported
1 Byte EncryptionRequested
1 Byte Padding length

Transition 10: Encryption succeeded from our perspective.

Data received
Length Content
n Bytes Padding
Data sent
Length Content
4 Byte MAGICVALUE_SYNC
1 Byte the selected encryption method: ENM_OBFUSCATION
1 Byte padding length
n Byte padding

Links

Protocol obfuscation

Ocaml and RC4

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox