|
You last visited: Today at 21:07
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.
05/27/2012, 20:15
|
#1
|
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.
|
|
|
05/27/2012, 20:17
|
#2
|
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
|
|
|
05/27/2012, 20:20
|
#3
|
elite*gold: 28
Join Date: Jun 2010
Posts: 2,225
Received Thanks: 868
|
Quote:
Originally Posted by Ultimation
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.
|
|
|
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?
|
|
|
05/28/2012, 09:58
|
#5
|
elite*gold: 0
Join Date: Dec 2010
Posts: 341
Received Thanks: 255
|
Looks good buddy!
|
|
|
05/28/2012, 10:32
|
#6
|
elite*gold: 28
Join Date: Jun 2010
Posts: 2,225
Received Thanks: 868
|
Quote:
Originally Posted by Arabian[GM]
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.
|
|
|
05/28/2012, 21:30
|
#7
|
elite*gold: 0
Join Date: Nov 2009
Posts: 380
Received Thanks: 58
|
hmm that is usefull  thank DN for sharing with us...
|
|
|
05/28/2012, 22:53
|
#8
|
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
|
|
|
05/29/2012, 01:03
|
#9
|
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?
|
|
|
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
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.
|
|
|
05/29/2012, 02:11
|
#11
|
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.
|
|
|
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
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)
|
|
|
05/29/2012, 08:44
|
#13
|
elite*gold: 28
Join Date: Jun 2010
Posts: 2,225
Received Thanks: 868
|
Quote:
Originally Posted by Korvacs
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.
|
|
|
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.
|
|
|
05/29/2012, 09:19
|
#15
|
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.
|
|
|
 |
|
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.
|
|