[Question]Common Mistakes in DH Key Exchange

12/24/2010 01:37 shitboi#1
Being struggling with my proxy for a while now. Still can't get past DH Key exchange. My worst night mare is that I don't even know where the problem lie, lol. I've re-trace my program over and over, and even re coded it 2 times. Still the exact same problem.

Since i cannot google enough information about my topic, I thought it would be easier if I can leech a bit of programming experience off the pros here.

Problem: Cannot decrypt client's Date packet after DH exchange.

Deduction: I failed to established a common shared key with client.

What i have tried:
I came up with a smaller model of my problem, that is, i wrote a test server and client that simply performs DH exchange using TQ's default P and G as my DH parameters. After DH exchange, server encrypts a message using the established shared key and send to client. Client decrypts and displays the message, then terminates. This test model is a success.

This makes me wonder, why is it that i can perform DH key exchange on my own test model but not with the TQClient/Server?

My blowfish cipher cannot be wrong, else i wont be able to extract out the server DH information correctly. At the same time, there is also little room to get wrong when performing DH exchange. Am i missing out on something? Please enlighten me on the possible errors I could have made.

If my question is vague to you, i'm glad to provide any additional info to make it clear. Btw, i wrote it in java.
12/24/2010 08:27 InfamousNoone#2
Is this for a proxy or a server?
12/24/2010 11:04 KraHen#3
I know that it`s a pretty lame idea, but are you performing the encryption/decryption both ways?
12/24/2010 11:58 ChingChong23#4
you could always perform a 'niggerrig'

take Pro4Never's C# proxy, strip it so as soon as the packets decrypted it sends it off to a connection on your Java proxy, you do what you want with it then send it back to the C# proxy which encrypts it and sends.

locally there won't really be a latency difference.
12/24/2010 13:47 shitboi#5
Quote:
Originally Posted by InfamousNoone View Post
Is this for a proxy or a server?
It is for a proxy

Quote:
Originally Posted by KraHen View Post
I know that it`s a pretty lame idea, but are you performing the encryption/decryption both ways?
Decrypt server packet, encrypt and send to client, same for client packet. what's wrong with that? Do you have a simpler way to get that done?

Quote:
Originally Posted by ChingChong23 View Post
you could always perform a 'niggerrig'

take Pro4Never's C# proxy, strip it so as soon as the packets decrypted it sends it off to a connection on your Java proxy, you do what you want with it then send it back to the C# proxy which encrypts it and sends.

locally there won't really be a latency difference.
If i have a good enough understand of the language, i'll simply rip off extract how he handled the packets, instead of going through the hassle of editing it so that only a portion of it works. Anyway, the benefit of making sure how things works is more rewarding than simply getting things to work :)
12/24/2010 13:49 KraHen#6
@ChingChong23 : Thanks :D I lol`d a lot on the name and the concept that you presented.
12/25/2010 07:52 InfamousNoone#7
Quote:
Originally Posted by ChingChong23 View Post
you could always perform a 'niggerrig'

take Pro4Never's C# proxy, strip it so as soon as the packets decrypted it sends it off to a connection on your Java proxy, you do what you want with it then send it back to the C# proxy which encrypts it and sends.

locally there won't really be a latency difference.
Merry Christmas my good man. You're my new hero.
12/25/2010 15:49 vDrag0n#8
Quote:
Originally Posted by ChingChong23 View Post
you could always perform a 'niggerrig'

take Pro4Never's C# proxy, strip it so as soon as the packets decrypted it sends it off to a connection on your Java proxy, you do what you want with it then send it back to the C# proxy which encrypts it and sends.

locally there won't really be a latency difference.
Now thats some hardcore WOP (Workaround Oriented Programming).
12/25/2010 19:56 shitboi#9
Well, be it a proxy or server or even client, the method/function/routine that are used to handle the key exchange procedure are all the same right?

That leads me to ask, the dh exchange used for conquer proxy is just like any ordinary dh exchange? the so called keys were handling are no more than base 16 string representation for a big integer right?

Also just to make sure both the private and public are not supposed to be negative right; since G^x mod P = X; negative key don't make much sense.
12/26/2010 21:13 InfamousNoone#10
Go forth young padwan.

Code:
        int ReceiveGameFromServerHandshake(JProxyData Client, Socket Socket, byte[] Buffer, int BufferSize)
        {
            Console.WriteLine("Receiving handshake from server...");
            int nrecv = recv(Socket, Buffer, 0, BufferSize);
            if (nrecv > 0)
            {
                byte[] rawHandshake = new byte[nrecv];
                Array.Copy(Buffer, rawHandshake, nrecv);
                rawHandshake = Client.clientEncryption.Decrypt(rawHandshake);

                CHandshake hs = new CHandshake(rawHandshake);

                Client.clientEncryption.CreateDHInstance(hs.GetP(), hs.GetG());
                Client.serverEncryption.CreateDHInstance(hs.GetP(), hs.GetG());
                Client.clientEncryption.GetDHInstance().AnotherPubKey = hs.GetPubKey();
                byte[] ourkey = Client.serverEncryption.GetDHInstance().GetPubKey();
                hs.SetPubKey(ourkey);

                byte[] ivec1 = new byte[16];
                byte[] ivec2 = new byte[16];

                Array.Copy(hs.GetClientIvec(), ivec1, 8);
                Array.Copy(hs.GetServerIvec(), 0, ivec1, 8, 8);
                Array.Copy(hs.GetServerIvec(), ivec2, 8);
                Array.Copy(hs.GetClientIvec(), 0, ivec2, 8, 8);

                Client.clientEncryption.TempIvec = ivec2;
                Client.serverEncryption.TempIvec = ivec1;

                Client.SendClient(hs.Rebuild());
                return nrecv;
            }
            return SOCKET_ERROR;
        }
Code:
        int ReceiveGameFromClientHandshake(JProxyData Client, Socket Socket, byte[] Buffer, int BufferSize)
        {
            Console.WriteLine("Receiving handshake from client...");
            int nrecv = recv(Socket, Buffer, 0, BufferSize);
            if (nrecv > 0)
            {
                byte[] rawHandshake = new byte[nrecv];
                Array.Copy(Buffer, rawHandshake, nrecv);
                rawHandshake = Client.serverEncryption.Decrypt(rawHandshake);

                CHandshakeReply hs = new CHandshakeReply(rawHandshake);
                byte[] ourkey = Client.clientEncryption.GetDHInstance().GetPubKey();

                CDHExchange dh = Client.serverEncryption.GetDHInstance();
                dh.AnotherPubKey = hs.GetPubKey();

                hs.SetPubKey(ourkey);
                Client.SendServer(hs.Rebuild());
                Client.serverEncryption.CompleteDHExchange();
                Client.clientEncryption.CompleteDHExchange();
                return nrecv;
            }
            return SOCKET_ERROR;
        }
Sorry for the mess in a file in advance, some of it (most) is converted up from C++.
12/27/2010 03:58 shitboi#11
Quote:
Originally Posted by InfamousNoone View Post
...
...
I have actually looked through the codes you have, I did it similarly. though with a different structure and language (java). Can you please run your program and tell me what is the length of your shared key? I happened to have 56bytes shared key since java enforced it that way. I am wondering if it has something to do with my shared key, thus resulting in unable to decrypt client packet.


this is a sample output
Code:
run:
Proxy Started : Listening for connection on port 9959
[GameProxy] : Thread started - Listening on 0.0.0.0/0.0.0.0:5816
[GameProxy] : Waiting for new clients to connect ... 
@Auth Proxy : Client connected
[AuthProxy] : Connecting to 208.96.34.46 on port 9959
[AuthProxy] : Auth Relay Complete
[GameProxy] : Client connected
[GameProxy] : Starting game service
[GameProxy] : Waiting for new clients to connect ... 
[GameProxy] : Started
[ServerHandler] packet recieved -> size: 347
{Client IV      } :4B A9 5F 58 89 54 C5 14 
{Server IV      } :9 B1 3C E6 6 A9 FE 88 
{Server P       } :A320A85EDD79171C341459E94807D71D39BB3B3F3B5161CA84894F3AC3FC7FEC317A2DDEC83B66D30C29261C6492643061AECFCF4A051816D7C359A6A7B7D8FB
{Server G       } :05
{ServerPublicKey} :8912FBC036037A731D2384A096A5469AB8D812329B78CBCCBB078D2915665DA3D4A44A1586AF7A716C0AF5A567EEAE5D5012A8ECF4E4BE313E2DD00CF6DCE94D  (128)
{ProxyPrivateKey} :E0E11E726F57BB4267DE0558BF518D4BB1552A62CBC930EC4AA9B9EFD704B262D2E2ECF78023794959DBF13EDA5510B9
{ProxyPublicKey } :655A389121670EA29169A6242F23400BCC8F417EF372E8779D5AC75C8E7725531558610B27A345BF0FC88C134CDE15BC3AC625B4E051810383E05E34ED88362A  (128)
[ServerHandler] packet relayed to client
[ClientHandler] packet recieved -> size: 187
{ClientPublicKey} :6C65ED0C9F8AEB3672A18413BAE6977946ED3A36A3B2ED6E7BDADF103CCBCFF878184AA77DAE5F178430C493ED2FC712C8F2FBAE0D54A6534CD4CA61C31465EC
ClientProxy shared key obtained
ServerProxy shared key obtained
[ClientHandler] packet relayed to server
[ClientHandler] packet recieved -> size: 36
[ClientHandler] Raw packet : 28 AA C5 7C 6C 59 7B C DC 58 FD 9E 5C FD C4 14 17 BE 6E 63 E4 FC 49 2 4F FD 77 57 0 F2 75 CB B2 DF 17 1 
[ClientHandler] Decrypted  : 2C E2 64 84 4F BD 9E 9F 5C F6 52 8B 5B AE D7 68 5A 36 B7 1C 6B 42 2B E9 68 ED 17 A3 AA FC 6B 16 6C B0 6B 3F 
[ClientHandler] ReEncrypted: 78 4D 4A 5C F8 13 BF C3 FB 4C 28 71 C7 E 5C B0 70 5E 80 9C 35 28 1A 3F 71 21 E3 3D 89 A9 A 4F 13 53 C9 31 
[ClientHandler] packet relayed to server
Well, that 36byte packet coming from client is the date packet, which doesn't make any sense after decryption. I have doubled checked the IVec, nothing seems wrong.

Hence the topic of this thread. A friend of mine who also happens to be developing proxy in java also faces the exact same issue.
12/27/2010 13:44 Korvacs#12
Once you've performed the key exchange and set both the keys do you synchronise the IV's?
12/27/2010 19:44 shitboi#13
Quote:
Originally Posted by Korvacs View Post
Once you've performed the key exchange and set both the keys do you synchronise the IV's?
What do you mean by sync the IVs? I am guessing you meant something like this:

ClientHandlerEncryptIV = ServerHandlerDecryptIV = serverIV
ClientHandlerDecrpytIV = ServerHandlerEncryptIV = clientIV

If so, i have done it already. My problem lies at the DH exchange part, somehow the key object generated by java's agreement object isn't usable in conquer's context. by unusable, i mean that the decryption result is unexpected.
12/28/2010 03:17 Korvacs#14
The IV's should be set to be like this:

Code:
ClientCrypt.Cryptor.EncryptIV = ServerCrypt.Cryptor.DecryptIV = ServerCrypt.ServerPacket.ClientIV;
ClientCrypt.Cryptor.DecryptIV = ServerCrypt.Cryptor.EncryptIV = ServerCrypt.ServerPacket.ServerIV;
You might want to try doing the same for yours aswell (yours are currently the reverse...of sorts), if that doesnt solve the problem can you supply a snippet of your cipher initialisation.
12/28/2010 10:14 shitboi#15
Quote:
Originally Posted by Korvacs View Post
The IV's should be set to be like this:

Code:
ClientCrypt.Cryptor.EncryptIV = ServerCrypt.Cryptor.DecryptIV = ServerCrypt.ServerPacket.ClientIV;
ClientCrypt.Cryptor.DecryptIV = ServerCrypt.Cryptor.EncryptIV = ServerCrypt.ServerPacket.ServerIV;
You might want to try doing the same for yours aswell (yours are currently the reverse...of sorts), if that doesnt solve the problem can you supply a snippet of your cipher initialisation.
yeah... i have set the IV properly. I just happened to have a weird architecture(poor planing) that might be confusing to you. However

my ClientHandlerEncryptIV corresponds to your ClientCrypt.Cryptor.EncryptIV,
and ServerHandlerDecryptIV corresponds to ServerCrypt.Cryptor.DecryptIV. With this i know my IVs are set correctly.

I just did a test. If i pause my proxy after relaying first packet from server, and perform a byte array search on conquer.exe using CheatEngine. i can only find my clientIV, but i cannot find the serverIV at all. I am guessing using the address of clientIV to read in an array of 16bytes, it should contain both clientIV and serverIV. If what i guessed is true, then the serverIV i have obtained is different from the one client has obtained.

I am not sure if you have that problem. I am just doing some really wild tests here and there hoping to find the cause of my problem.