Register for your free account! | Forgot your password?

Go Back   elitepvpers > MMORPGs > Conquer Online 2 > CO2 Private Server > CO2 PServer Guides & Releases
You last visited: Today at 21:07

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



Clean KeyExchange Implementation [SSL]

Discussion on Clean KeyExchange Implementation [SSL] within the CO2 PServer Guides & Releases forum part of the CO2 Private Server category.

Reply
 
Old   #1
 
_DreadNought_'s Avatar
 
elite*gold: 28
Join Date: Jun 2010
Posts: 2,225
Received Thanks: 868
Clean KeyExchange Implementation [SSL]

Hey,

This is what I think a much cleaner KeyExchange, and yes it's using SSL.

KeyExchange.cs
Code:
using OpenSSL;
using PoisonCO.Core.PacketProcessor.Structures;

namespace PoisonCO.Game.Crypto
{
    public class KeyExchange
    {
        public DH Exchange;
        private readonly string _p, _g;
        public ServerKeyPacket ServerKeyPacket;
        public byte[] ClientIV = new byte[8];
        public byte[] ServerIV = new byte[8];
        private GameCryptographer _cryptography;

        public KeyExchange()
        {
            _p = "E7A69EBDF105F2A6BBDEAD7E798F76A209AD73FB466431E2E7352ED262F8C558F10BEFEA977DE9E21DCEE9B04D245F300ECCBBA03E72630556D011023F9E857F";
            _g = "05";
            Exchange = new DH(BigNumber.FromHexString(_p), BigNumber.FromHexString(_g));
            Exchange.GenerateKeys();
            InitalizeKeyPacket(ServerIV, ClientIV, _p, _g, Exchange.PublicKey.ToHexString());
        }
        public void HandleClientKeyPacket(string pKey, GameClient client)
        {
            _cryptography = client.GameCrypto;
            _cryptography.SetKey(ComputeKey(pKey));
            SetIVs(_cryptography);
        }
        public void SetIVs(GameCryptographer crypto)
        {
            crypto.SetIvs(ClientIV, ServerIV);
        }
        public byte[] ComputeKey(string pKey)
        {
            return Exchange.ComputeKey(BigNumber.FromHexString(pKey));
        }
        public void InitalizeKeyPacket(byte[] serverIV1, byte[] serverIV2, string p, string g, string serverPublicKey)
        {
            ServerKeyPacket = new ServerKeyPacket
                                  {
                                      ServerPublicKey = serverPublicKey,
                                      ServerIV1 = serverIV1,
                                      ServerIV2 = serverIV2,
                                      P = p,
                                      G = g
                                  };
        }
    }
}
ServerKeyPacket.cs
Code:
using System;
using System.IO;

namespace PoisonCO.Core.PacketProcessor.Structures
{
    public class ServerKeyPacket
    {
        private byte[] _serverIV1, _serverIV2;
        private string _p, _g, _serverPublicKey;

        public ServerKeyPacket()
        {
            
        }
        public byte[] ServerIV1
        {
            get { return _serverIV1; }
            set { _serverIV1 = value; }
        }
        public byte[] ServerIV2
        {
            get { return _serverIV2; }
            set { _serverIV2 = value; }
        }
        public string P
        {
            get { return _p; }
            set { _p = value; }
        }
        public string G
        {
            get { return _g; }
            set { _g = value; }
        }
        public string ServerPublicKey
        {
            get { return _serverPublicKey; }
            set { _serverPublicKey = value; }
        }
        public byte[] ToBytes()
        {
            const int padLen = 11;
            const int junkLen = 12;
            const string tqs = "TQServer";
            byte[] packet;
            var ms = new MemoryStream();
            var pad = new byte[padLen];
            Kernel.Random.NextBytes(pad);
            var junk = new byte[junkLen];
            Kernel.Random.NextBytes(junk);
            var size = 47 + _p.Length + _g.Length + _serverPublicKey.Length + 12 + 8 + 8;
            using (var br = new BinaryWriter(ms))
            {
                br.Write(pad);
                br.Write(size - padLen);
                br.Write((UInt32)junkLen);
                br.Write(junk);
                br.Write((UInt32)_serverIV2.Length);
                br.Write(_serverIV2);
                br.Write((UInt32)_serverIV1.Length);
                br.Write(_serverIV1);
                br.Write((UInt32)_p.ToCharArray().Length);
                foreach (var fP in _p.ToCharArray())
                {
                    br.BaseStream.WriteByte((byte)fP);
                }
                br.Write((UInt32)_g.ToCharArray().Length);
                foreach (var fG in _g.ToCharArray())
                {
                    br.BaseStream.WriteByte((byte)fG);
                }
                br.Write((UInt32)_serverPublicKey.ToCharArray().Length);
                foreach (var spk in _serverPublicKey.ToCharArray())
                {
                    br.BaseStream.WriteByte((byte)spk);
                }
                foreach (var tq in tqs.ToCharArray())
                {
                    br.BaseStream.WriteByte((byte)tq);
                }
                packet = ms.ToArray();
                ms.Close();
            }
            return packet;
        }
    }
}
ClientKeyPacket.cs
Code:
using System.IO;
using System.Text;

namespace PoisonCO.Core.PacketProcessor.Structures
{
    public class ClientKeyPacket
    {
        private byte[] _junk1, _junk3;
        private uint _junk2;
        private int _junkLength, _length;
        private byte[] _pKey;
        public ClientKeyPacket(byte[] data)
        {
            var stream = new MemoryStream(data);
            using (var rdr = new BinaryReader(stream))
            {
                //Junk
                _junk1 = rdr.ReadBytes(7);
                _junk2 = rdr.ReadUInt32();
                _junkLength = rdr.ReadInt32();
                _junk3 = rdr.ReadBytes(_junkLength);

                //Useful stuff
                _length = rdr.ReadInt32();
                _pKey = rdr.ReadBytes(_length);
                stream.Close();
            }
        }

        public byte[] Junk1
        {
            get { return _junk1; }
        }
        public uint Junk2
        {
            get { return _junk2;  }
        }
        public int JunkLength
        {
            get { return _junkLength; }
        }
        public byte[] Junk3
        {
            get { return _junk3; }
        }
        public int Length
        {
            get { return _length; }
        }
        public string PublicKey
        {
            get { return Encoding.ASCII.GetString(_pKey); }
        }
    }
}
Usage:
Upon connection to the game server
Code:
Client.Send(Client.Exchange.ServerKeyPacket.ToBytes());
How I handle it:
Code:
switch (Client.IsExchanging)
            {
                case false:
                    {
                        Client.IsExchanging = true;
                        var pkt = new ClientKeyPacket(Packet);
                        Client.Exchange.HandleClientKeyPacket(pkt.PublicKey, Client);
                        break;
                    }
                case true:
                    {
                        Core.PacketProcessor.Process.PacketSplitter(Packet, Client);
                        break;
                    }
            }
Enjoy.
_DreadNought_ is offline  
Thanks
4 Users
Old 05/27/2012, 20:17   #2
 
Ultimation's Avatar
 
elite*gold: 0
Join Date: Mar 2005
Posts: 1,430
Received Thanks: 1,586
very nice release DN, though u dont need a switch statement for a bool If(!)
but otherwise, nice and clean
Ultimation is offline  
Thanks
1 User
Old 05/27/2012, 20:20   #3
 
_DreadNought_'s Avatar
 
elite*gold: 28
Join Date: Jun 2010
Posts: 2,225
Received Thanks: 868
Quote:
Originally Posted by Ultimation View Post
very nice release DN, though u dont need a switch statement for a bool If(!)
but otherwise, nice and clean
Thanks, and yeah, I simply went with a case statement due to the fact I personally prefer'd it and I cannot see any performance issues with it(I don't count 0.1ms a issue), so therefore I just went with personal preference.
_DreadNought_ is offline  
Old 05/28/2012, 08:36   #4
 
elite*gold: 0
Join Date: Mar 2010
Posts: 18
Received Thanks: 0
Hello

Is it possible to explain more about it?
Arabian[GM] is offline  
Old 05/28/2012, 09:58   #5
 
.Kinshi's Avatar
 
elite*gold: 0
Join Date: Dec 2010
Posts: 341
Received Thanks: 255
Looks good buddy!
.Kinshi is offline  
Thanks
1 User
Old 05/28/2012, 10:32   #6
 
_DreadNought_'s Avatar
 
elite*gold: 28
Join Date: Jun 2010
Posts: 2,225
Received Thanks: 868
Quote:
Originally Posted by Arabian[GM] View Post
Hello

Is it possible to explain more about it?
This is the Diffie Hellman Exchange, - Dreadful spelling.

It is a KeyExchange the client & server take part in, The client sends some information on GameReceive before sending an actual game packet that the server can then generate a valid reply & set up the CAST5 Encryption correctly(sets its keys), This implementation is a much clearner & sleek implementation that what I've seen - Using OpenSSL, I don't actually have the BIgNumber & DH c# class out of OpenSSL, Nor could I find it or be bothered to open it up in BouncyCastle.

This also has packet structures unlike most KeyExchanges I've seen.

If you want to find out more just goole DH KeyExchange.
_DreadNought_ is offline  
Old 05/28/2012, 21:30   #7
 
Sp!!ke's Avatar
 
elite*gold: 0
Join Date: Nov 2009
Posts: 380
Received Thanks: 58
hmm that is usefull thank DN for sharing with us...
Sp!!ke is offline  
Old 05/28/2012, 22:53   #8
 
_DreadNought_'s Avatar
 
elite*gold: 28
Join Date: Jun 2010
Posts: 2,225
Received Thanks: 868
Just notice how this > Other SSL Implementation & includes packet structures for the exchange
_DreadNought_ is offline  
Old 05/29/2012, 01:03   #9


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,126
Received Thanks: 2,518
This looks basically the same as every other key exchange ive ever seen, how is this different?

Comparing this to other existing examples this is actually more messy and less readable?
Korvacs is offline  
Old 05/29/2012, 01:53   #10
 
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,380
Quote:
Originally Posted by Korvacs View Post
This looks basically the same as every other key exchange ive ever seen, how is this different?

Comparing this to other existing examples this is actually more messy and less readable?
I think it's because he standardized it more towards packet structures people are familiar with. I agree it's more messy then some of the less... common implementations but it's definitely clearer and more organized then many of the public sources out there. Sort of a middle ground.
pro4never is offline  
Old 05/29/2012, 02:11   #11
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,282
Received Thanks: 4,191
Exchange shouldn't be checked for every single packet being handled. It should be handled only on the first packet receive in a separate socket event. In other words, Begin Receive using one method, then at the end of the exchange method, begin receive with another method for handling packets.
Spirited is offline  
Old 05/29/2012, 02:18   #12
 
elite*gold: 21
Join Date: Jul 2005
Posts: 9,193
Received Thanks: 5,380
Quote:
Originally Posted by Fаng View Post
Exchange shouldn't be checked for every single packet being handled. It should be handled only on the first packet receive in a separate socket event. In other words, Begin Receive using one method, then at the end of the exchange method, begin receive with another method for handling packets.
^

Has always bugged me how few sources handle it incorrectly (my own former work being part of the problem)
pro4never is offline  
Old 05/29/2012, 08:44   #13
 
_DreadNought_'s Avatar
 
elite*gold: 28
Join Date: Jun 2010
Posts: 2,225
Received Thanks: 868
Quote:
Originally Posted by Korvacs View Post
This looks basically the same as every other key exchange ive ever seen, how is this different?

Comparing this to other existing examples this is actually more messy and less readable?
Let's compare shall we?

Code:
using OpenSSL;
using PoisonCO.Core.PacketProcessor.Structures;

namespace PoisonCO.Game.Crypto
{
    public class KeyExchange
    {
        public DH Exchange;
        private readonly string _p, _g;
        public ServerKeyPacket ServerKeyPacket;
        public byte[] ClientIV = new byte[8];
        public byte[] ServerIV = new byte[8];
        private GameCryptographer _cryptography;

        public KeyExchange()
        {
            _p = "E7A69EBDF105F2A6BBDEAD7E798F76A209AD73FB466431E2E7352ED262F8C558F10BEFEA977DE9E21DCEE9B04D245F300ECCBBA03E72630556D011023F9E857F";
            _g = "05";
            Exchange = new DH(BigNumber.FromHexString(_p), BigNumber.FromHexString(_g));
            Exchange.GenerateKeys();
            InitalizeKeyPacket(ServerIV, ClientIV, _p, _g, Exchange.PublicKey.ToHexString());
        }
        public void HandleClientKeyPacket(string pKey, GameClient client)
        {
            _cryptography = client.GameCrypto;
            _cryptography.SetKey(ComputeKey(pKey));
            SetIVs(_cryptography);
        }
        public void SetIVs(GameCryptographer crypto)
        {
            crypto.SetIvs(ClientIV, ServerIV);
        }
        public byte[] ComputeKey(string pKey)
        {
            return Exchange.ComputeKey(BigNumber.FromHexString(pKey));
        }
        public void InitalizeKeyPacket(byte[] serverIV1, byte[] serverIV2, string p, string g, string serverPublicKey)
        {
            ServerKeyPacket = new ServerKeyPacket
                                  {
                                      ServerPublicKey = serverPublicKey,
                                      ServerIV1 = serverIV1,
                                      ServerIV2 = serverIV2,
                                      P = p,
                                      G = g
                                  };
        }
    }
}
Code:
using System;
using System.IO;
using System.Text;

namespace Conquer_Online_Server.Network.GamePackets
{
    public static class DHKeyExchange
    {
        public class ServerKeyExchange
        {
            OpenSSL.DH _keyExchange;
            byte[] _serverIv;
            byte[] _clientIv;

            public byte[] CreateServerKeyPacket()
            {
                _clientIv = new byte[8];
                _serverIv = new byte[8];
                //string P = "E7A69EBDF105F2A6BBDEAD7E798F76A209AD73FB466431E2E7352ED262F8C558F10BEFEA977DE9E21DCEE9B04D245F300ECCBBA03E72630556D011023F9E857F";
                string P = "A320A85EDD79171C341459E94807D71D39BB3B3F3B5161CA84894F3AC3FC7FEC317A2DDEC83B66D30C29261C6492643061AECFCF4A051816D7C359A6A7B7D8FB";
                string G = "05";
                _keyExchange = new OpenSSL.DH(OpenSSL.BigNumber.FromHexString(P), OpenSSL.BigNumber.FromHexString(G));
                _keyExchange.GenerateKeys();
                return GeneratePacket(_serverIv, _clientIv, P, G, _keyExchange.PublicKey.ToHexString());
            }

            public Cryptography.GameCryptography HandleClientKeyPacket(string PublicKey, Cryptography.GameCryptography cryptographer)
            {
                byte[] key = _keyExchange.ComputeKey(OpenSSL.BigNumber.FromHexString(PublicKey));
                cryptographer.SetKey(key);
                cryptographer.SetIvs(_clientIv, _serverIv);
                return cryptographer;
            }
            public byte[] GeneratePacket(byte[] ServerIV1, byte[] ServerIV2, string P, string G, string ServerPublicKey)
            {
                int PAD_LEN = 11;
                int _junk_len = 12;
                string tqs = "TQServer";
                MemoryStream ms = new MemoryStream();
                byte[] pad = new byte[PAD_LEN];
                ServerBase.Kernel.Random.NextBytes(pad);
                byte[] junk = new byte[_junk_len];
                ServerBase.Kernel.Random.NextBytes(junk);
                int size = 47 + P.Length + G.Length + ServerPublicKey.Length + 12 + 8 + 8;
                BinaryWriter bw = new BinaryWriter(ms);
                bw.Write(pad);
                bw.Write(size - PAD_LEN);
                bw.Write((UInt32)_junk_len);
                bw.Write(junk);
                bw.Write((UInt32)ServerIV2.Length);
                bw.Write(ServerIV2);
                bw.Write((UInt32)ServerIV1.Length);
                bw.Write(ServerIV1);
                bw.Write((UInt32)P.ToCharArray().Length);
                foreach (char fP in P.ToCharArray())
                {
                    bw.BaseStream.WriteByte((byte)fP);
                }
                bw.Write((UInt32)G.ToCharArray().Length);
                foreach (char fG in G.ToCharArray())
                {
                    bw.BaseStream.WriteByte((byte)fG);
                }
                bw.Write((UInt32)ServerPublicKey.ToCharArray().Length);
                foreach (char SPK in ServerPublicKey.ToCharArray())
                {
                    bw.BaseStream.WriteByte((byte)SPK);
                }
                foreach (char tq in tqs.ToCharArray())
                {
                    bw.BaseStream.WriteByte((byte)tq);
                }
                byte[] Packet = new byte[ms.Length];
                Packet = ms.ToArray();
                ms.Close();
                return Packet;
            }
        }
        public class ClientKeyPacket
        {
            private static int PAD_LEN = 7;
            private uint _junk_len;
            string _publicKey;

            public ClientKeyPacket(byte[] buffer)
            {
                MemoryStream ms = new MemoryStream(buffer);
                BinaryReader br = new BinaryReader(ms);
                br.BaseStream.Seek(PAD_LEN, SeekOrigin.Begin);
                uint len = br.ReadUInt32();
                _junk_len = br.ReadUInt32();
                byte[] junk = br.ReadBytes((int)_junk_len);
                _publicKey = Encoding.ASCII.GetString(br.ReadBytes(br.ReadInt32()));
            }

            public string PublicKey
            {
                get { return _publicKey; }
            }
        }
    }
}
Looks abit different to me, and messy? That's your opinion, but I am going to have to say, that is no way near as messy as the 2nd example, and if you can find a better one, then provide it as evidence or its pointless making a comment really.

@Fang & @Pro4Never: As for doing the check, meh, I did actually consider that but I guess I just got lazy, I wasn't really worried about the extra 0.01ms in time to be honest.
_DreadNought_ is offline  
Old 05/29/2012, 09:18   #14
 
elite*gold: 0
Join Date: Dec 2011
Posts: 1,537
Received Thanks: 785
I only dislike the fact you used a stream.
I don't have a username is offline  
Old 05/29/2012, 09:19   #15


 
Korvacs's Avatar
 
elite*gold: 20
Join Date: Mar 2006
Posts: 6,126
Received Thanks: 2,518
Code:
public class KeyExchange
    {
        public ClientKeyPacket CKeyPacket;
        public byte[] ClientIV = new byte[8];
        public DH Exchange;
        public bool Exchanged;
        public byte[] ServerIV = new byte[8];
        public ServerKeyPacket SKeyPacket;

        public KeyExchange()
        {
            Random random = new Random();
            random.NextBytes(this.ServerIV);
            random.NextBytes(this.ClientIV);
            string str = "E7A69EBDF105F2A6BBDEAD7E798F76A209AD73FB466431E2E7352ED262F8C558F10BEFEA977DE9E21DCEE9B04D245F300ECCBBA03E72630556D011023F9E857F";
            string str2 = "05";
            this.Exchange = new DH(BigNumber.FromHexString(str), BigNumber.FromHexString(str2));
            this.Exchange.GenerateKeys();
            this.SKeyPacket = new ServerKeyPacket(this.ClientIV, this.ServerIV, str, str2, this.Exchange.PublicKey.ToHexString());
        }

        public void HandleClientKeyPacket(ClientKeyPacket CKeyPacket, GameCryptographer Cryptographer)
        {
            Cryptographer.Blowfish.SetKey(this.Exchange.ComputeKey(BigNumber.FromHexString(CKeyPacket.PublicKey)));
            Cryptographer.Blowfish.EncryptIV = new byte[8];
            Cryptographer.Blowfish.DecryptIV = new byte[8];
        }

        public void ResetIVs(GameCryptographer Cryptographer)
        {
            Cryptographer.Blowfish.DecryptIV = new byte[8];
            Cryptographer.Blowfish.EncryptIV = new byte[8];
        }
    }
^ Publicly available.
Korvacs is offline  
Reply


Similar Threads Similar Threads
Blowfish CFB64 (C++ implementation)
05/04/2012 - CO2 PServer Guides & Releases - 6 Replies
In a project I have (not CO2 related), I use Blowfish with the Cipher Feedback (CFB64) mode. So, I made a C++ implementation. As the project will be open-source at some point. I don't care of releasing my implementation. Header: // * ************************************************** ********** // * * START: blowfish.h * // * ************************************************** ********** // *...
[Question] KeyExchange
05/09/2011 - CO2 Private Server - 2 Replies
Hey everyone, can anyone please Explain to me how is the KeyExchange working in the new Clients !! string P = "E7A69EBDF105F2A6BBDEAD7E798F76A209AD73FB4664 31E2E7352ED262F8C558F10BEFEA977DE9E21DCEE9B04D245F 300ECCBBA03E72630556D011023F9E857F"; string G = "05"; string tqs = "TQServer"; and like what is the P,G and tqs refering to!? or how can i use it
Zoom Hack [implementation]
01/22/2010 - GW Exploits, Hacks, Bots, Tools & Macros - 34 Replies
Just a small Zoom Hack. How to do: 1. Run Guild Wars (you won't be able to run the hack without running instance of Guild Wars) 2. choose an Value (69-75).* 3. press 'Freeze'.
Zoom Hack Implementation [NEW!]
12/30/2009 - GW Exploits, Hacks, Bots, Tools & Macros - 36 Replies
Hello Boy's and Girl's. Some of you People know my old Zoom Hack http://www.elitepvpers.com/forum/gw-exploits-hacks- bots-tools-macros/233285-zoom-hack-implementation. html This one was working well, but i decided to recode and review it. Now it works with Scrollwheel and is Hotkeycontroled. At the moment you can't move the Camera but it'll come in the next update. Anyway, you can freez/unfreez it in any Zoom. http://www3.pic-upload.de/21.06.09/lk725d.jpg



All times are GMT +1. The time now is 21:08.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.