BlowFish

02/13/2011 08:01 Mr_PoP#1
is there anycode for Blowfish here in C++ works with the later clients?! like the one in ExodusBinaries?
02/13/2011 08:57 tanelipe#2
This is a quote from my old post. It does contain some major errors, it does work but it leaks like a ol' pipe so it should only be used as reference.

Quote:

As usual this has no interest in private server section so here it goes, it's not finished yet. If you see errors / places where it could be better, post here. It's not tested but it should work unless there's a major fuck-up somewhere.

Blowfish.h

PHP Code:
#pragma once

#include <openssl/blowfish.h>
#pragma comment(lib, "libeay32.lib")

class CBlowfish
{
private:
    
unsigned char *DecryptIV;
    
unsigned char *EncryptIV;

    
int DecryptCounter;
    
int EncryptCounter;

    
BF_KEY *Key;
public:
    
CBlowfish(unsigned char *Dataint Length);
    ~
CBlowfish(void);

    
unsigned charEncrypt(unsigned char *Dataint Length);
    
unsigned charDecrypt(unsigned char *Dataint Length);

    
void SetKey(unsigned char *Dataint Length);
    
void SetIVs(unsigned char *DecryptIVunsigned char *EncryptIV);
}; 
Blowfish.cpp

PHP Code:
#include "StdAfx.h"
#include "Blowfish.h"

CBlowfish::CBlowfish(unsigned char *Dataint Length)
{
    
DecryptIV = new unsigned char[8];
    
EncryptIV = new unsigned char[8];
    
DecryptCounter 0;
    
EncryptCounter 0;

    
Key = new BF_KEY();
    
BF_set_key(KeyLengthData);
}

CBlowfish::~CBlowfish(void)
{
    
delete[] DecryptIV;
    
delete[] EncryptIV;
    
delete[] Key;
}

unsigned charCBlowfish::Encrypt(unsigned char *Dataint Length)
{
    
unsigned charOut = new unsigned char[Length];
    
BF_cfb64_encrypt(DataOutLengthKeyEncryptIV, &EncryptCounter1);
    return 
Out;
}
unsigned charCBlowfish::Decrypt(unsigned char *Dataint Length)
{
    
unsigned charOut = new unsigned char[Length];
    
BF_cfb64_encrypt(DataOutLengthKeyDecryptIV, &DecryptCounter0);
    return 
Out;
}
void CBlowfish::SetKey(unsigned char *Dataint Length)
{
    
BF_set_key(KeyLengthData);
    
DecryptCounter 0;
    
EncryptCounter 0;
}
void CBlowfish::SetIVs(unsigned char *DecryptIVunsigned char *EncryptIV)
{
    
memcpy(this->DecryptIVDecryptIV8);
    
memcpy(this->EncryptIVEncryptIV8);

DH.h

PHP Code:
#pragma once

#include <openssl/dh.h>
#include <openssl/bn.h>
class CDH
{
private:
    
DH *dh;
public:
    
CDH(BIGNUM *PBIGNUM *G);
    ~
CDH(void);

    
unsigned charComputeKey(BIGNUM *PublicKey);
    
void GenerateKeys();


    
void SetG(BIGNUM *G);
    
void SetP(BIGNUM *P);
    
void SetPrivate(BIGNUM *PrivateKey);
    
void SetPublic(BIGNUM *PublicKey);

    
BIGNUMGetG();
    
BIGNUMGetP();
    
BIGNUMGetPrivate();
    
BIGNUMGetPublic();

    
__declspec(property(get GetGput SetG)) BIGNUM *G;
    
__declspec(property(get GetPput SetP)) BIGNUM *P;

    
__declspec(property(get GetPrivateput SetPrivate)) BIGNUM *PrivateKey;
    
__declspec(property(get GetPublicput SetPublic)) BIGNUM *PublicKey;
}; 
DH.cpp

PHP Code:
#include "StdAfx.h"
#include "DH.h"

CDH::CDH(BIGNUM *PBIGNUM *G)
{
    
dh DH_new();
    
dh->BN_dup(P);
    
dh->BN_dup(G);
}

unsigned charCDH::ComputeKey(BIGNUM *PublicKey)
{
    
unsigned char *Key = new unsigned char[DH_size(dh)];
    
DH_compute_key(KeyPublicKeydh);
    return 
Key;
}
void CDH::GenerateKeys() 
{
    
DH_generate_key(dh);
}

void CDH::SetG(BIGNUM *G)
{
    
dh->BN_dup(G);
}

void CDH::SetP(BIGNUM *P)
{
    
dh->BN_dup(P);
}
void CDH::SetPrivate(BIGNUMPrivateKey)
{
    
dh->priv_key BN_dup(PrivateKey);
}
void CDH::SetPublic(BIGNUMPublicKey)
{
    
dh->pub_key BN_dup(PublicKey);
}
BIGNUMCDH::GetP()
{
    return 
dh->p;
}
BIGNUMCDH::GetG()
{
    return 
dh->g;
}
BIGNUMCDH::GetPrivate()
{
    return 
dh->priv_key;
}
BIGNUMCDH::GetPublic()
{
    return 
dh->pub_key;
}

CDH::~CDH(void)
{
    
delete[] dh;

Quote:
GameCryptography.h
PHP Code:
#pragma once

#include "Blowfish.h"
class CGameCryptography
{
public:
    
CGameCryptography(void);
    ~
CGameCryptography(void);

    
CBlowfish *bf;    

    
unsigned charEncrypt(unsigned char *Packetint Length);
    
unsigned charDecrypt(unsigned char *Packetint Length);
}; 
GameCryptography.cpp
PHP Code:
#include "StdAfx.h"
#include "GameCryptography.h"

CGameCryptography::CGameCryptography(void)
{
    
char *szInitialKey "DR654dt34trg4UI6";
    
bf = new CBlowfish(reinterpret_cast<unsigned char*>(szInitialKey), 16);
    
/*char *szInitialKey = "DR654dt34trg4UI6";
    unsigned char *Key = new unsigned char[sizeof(szInitialKey)];
    for(int i = 0; i < sizeof(szInitialKey); i++)
        Key[i] = (unsigned char)szInitialKey[i];
    bf = new CBlowfish(Key, 16);
    reinterpret_cast<*/
}

CGameCryptography::~CGameCryptography(void)
{
    
delete[] bf;
}
unsigned char *CGameCryptography::Encrypt(unsigned char *Packetint Length)
{
    return 
bf->Encrypt(PacketLength);
}
unsigned char *CGameCryptography::Decrypt(unsigned char *Packetint Length)
{
    return 
bf->Decrypt(PacketLength);


Handshake.h
PHP Code:
#pragma once

#include "PacketReader.h"

class Handshake
{
public:
    
Handshake(void) { }
    ~
Handshake(void) { }

    
unsigned char *ServerIV, *ClientIV;
    
char *P, *G, *PublicKey;
    
void Process(unsigned char *Packet
    {
        
PacketReader *Reader = new PacketReader(Packetsizeof(Packet), 15);
        
Reader->Advance(Reader->ReadDWord());
        
ServerIV Reader->ReadBytes(Reader->ReadDWord());
        
ClientIV Reader->ReadBytes(Reader->ReadDWord());
        
Reader->ReadString(Reader->ReadDWord());
        
Reader->ReadString(Reader->ReadDWord());
        
PublicKey Reader->ReadString(Reader->ReadDWord());
    }
}; 
HandshakeReply.h
PHP Code:
#pragma once

#include "PacketReader.h"

class HandshakeReply
{
public:
    
HandshakeReply(void) { }
    ~
HandshakeReply(void) { }

    
char *PublicKey;
    
void Process(unsigned char *Packet
    {
        
PacketReader *Reader = new PacketReader(Packetsizeof(Packet), 11);
        
Reader->Advance(Reader->ReadDWord());
        
PublicKey Reader->ReadString(Reader->ReadDWord());
    }
}; 
PacketReader.h
PHP Code:
#pragma once

class PacketReader
{
private:
    
unsigned char *Packet;


public:    
    
unsigned long Index;
    
PacketReader(unsigned char *Packetint Lengthint Position 0)
    {
        
this->Packet Packet;
        
this->Index Position;
    }
    
void Advance(unsigned long Length)
    {
        
Index += Length;
    }
    
unsigned long ReadDWord()
    {
        
unsigned long Value = *((unsigned long*)(Packet Index));
        
Index += 4;
        return 
Value;
    }
    
unsigned charReadBytes(unsigned long Length)
    {
        
unsigned char *Value = new unsigned char[Length];
        
memcpy(Value, (Packet Index), Length);
        
Index += Length;
        return 
Value;
    }
    
char *ReadString(unsigned long Length)
    {
        
charValue = new char[Length];
        for(
int i 0Lengthi++)
            
Value[i] = (char)Packet[Index i];
        
Index += Length;
        
Value[Length] = 0x00;
        return 
Value;
    }
    ~
PacketReader(void)
    {
        
delete[] Packet;
    }
}; 


EDIT: Might have found a fixed version --> attachment
02/13/2011 18:55 Mr_PoP#3
Thanks for your help but am facing a prob can u take a look and tell me what am doing wrong?

Code:
       GameCipher test("DR654dt34trg4UI6");
	for(;;)
	{
		if((sConnect=accept(sListen,(SOCKADDR*)&addr,&addrlen)) != INVALID_SOCKET)
		{
			Print("Socket Connected -> %s",inet_ntoa(addr.sin_addr));
			char rSeed[9];
			rPassSeed(rSeed);
			char buf[1096];
			int buflen=strlen(buf);
			send(sListen,rSeed,8,0);
			recv(sListen,buf,buflen,0);
			test.Decrypt((unsigned char *)buf,(unsigned char *)buf,buflen);
			cout << buf;
		}
Result:
[Only registered and activated users can see links. Click Here To Register...]
thanks i appreciate ur help :)
02/13/2011 19:47 unknownone#4
You can't just ouput a binary stream like that. You need to convert it to hexidecimal to be readable at all.

Code:
#include <iostream>
#include <iomanip>

void output_hex (std::ostream& out, uint8_t const* const buf, int len) {
    for (int i=0;i<len;i++)
        out << std::noshowbase
            << std::hex
            << std::setfill ('0')
            << std::setw (2)
            << static_cast<int> (buf[i])
            << " ";
}

//
output_hex (cout, buf, buflen);
02/13/2011 19:56 Mr_PoP#5
Quote:
Originally Posted by unknownone View Post
You can't just ouput a binary stream like that. You need to convert it to hexidecimal to be readable at all.

Code:
#include <iostream>
#include <iomanip>

void output_hex (std::ostream& out, uint8_t const* const buf, int len) {
    for (int i=0;i<len;i++)
        out << std::noshowbase
            << std::hex
            << std::setfill ('0')
            << std::setw (2)
            << static_cast<int> (buf[i])
            << " ";
}

//
output_hex (cout, buf, buflen);
but am trying to decrypt what am geting from the client using Blowfish when i used the function u showed me here is the reslut:
[Only registered and activated users can see links. Click Here To Register...]
02/13/2011 20:02 unknownone#6
Are you expecting to read plain text? Because that won't happen. The protocol is a binary one, and has very little text in it. For starters, fix this:

Get the result from recv(), which is the actual number of bytes receive (rather than the size of the buffer). Then output_hex (cout, buf, recv_len); You should get something a bit more readable.
02/13/2011 20:21 Mr_PoP#7
Quote:
Originally Posted by unknownone View Post
Are you expecting to read plain text? Because that won't happen. The protocol is a binary one, and has very little text in it. For starters, fix this:

Get the result from recv(), which is the actual number of bytes receive (rather than the size of the buffer). Then output_hex (cout, buf, recv_len); You should get something a bit more readable.
so lets make every thing clear i send to the client:
Code:
const int Seed=74185296;
send(sListen,(char *)Seed,8,0);
i recv() what ever i will recv. then i take the buf into the Blowfish then it should decrypt every thing but the password right1?
02/13/2011 20:27 unknownone#8
You don't simple send the Seed value like that. You must structure it into the packet you posted in the other thread.

Code:
typedef struct packetSeed
{
    unsigned short Length; // 0x8
    unsigned short Type; // 0x423
    unsigned int Seed; // random
} * PPACKETSEED;

packetSeed * packet = new packetSeed();
packet->length = 8;
packet->type = 0x423;
packet->Seed = 74185296;
send(s, (uint8_t*)packet, sizeof(packetSeed), 0);
delete packet;
Oh, and I noticed you're sending/recieving on your listen socket. You shouldn't do that. You should be send/receiving on the connected socket that was returned in the call to accept(); I'd suggest go reading Beej's guide to network programming for further details.
02/13/2011 20:32 Mr_PoP#9
Quote:
Originally Posted by unknownone View Post
You don't simple send the Seed value like that. You must structure it into the packet you posted in the other thread.

Code:
typedef struct packetSeed
{
    unsigned short Length; // 0x8
    unsigned short Type; // 0x423
    unsigned int Seed; // random
} * PPACKETSEED;

packetSeed * packet = new packetSeed();
packet->length = 8;
packet->type = 0x423;
packet->Seed = 74185296;
send(s, (uint8_t*)packet, sizeof(packetSeed), 0);
delete packet;
Oh, and I noticed you're sending/recieving on your listen socket. You shouldn't do that. You should be send/receiving on the connected socket that was returned in the call to accept(); I'd suggest go reading Beej's guide to network programming for further details.
a question if i may why should i send it by this way?

Edit: reading the Beej's guide also when i used sConnect to send and recv the cllient crashs!?
02/13/2011 20:45 unknownone#10
Because that's what the client expects to receive. The particular pieces of data are required in order to the client to be able to interpret the data you are sending.

For starters, the length field of the packet is required in TCP (stream based) communication, because the client must be able to recognise where a particular piece of information starts and ends. If you call send 5 times on a server, that doesn't necessarily mean that the client will need to call recv 5 times to recv those 5 pieces of data. It may only need to call it once, or it may need to call it 10 times. It depends on the load on the network, it cannot be decided beforehand where each send was sent in the stream. So we add a length to each "send" so that the receiver can interpret the data and decide where each piece of sent information begins and ends.

As for the type - This is a primitive that decides what the receiver should do with the data. There's lots of different pieces of data you can send that do different functions (for example, one might contain login information, another might contain some chat information). The type primitive just identifies each piece of information so that it can be mapped to a function that is to be performed on the payload. (In this case, is the seed).

So if you send data as described. The client will first read the length, to determine when to stop receiving for this particular piece of data. It will then read the type, and see it is the Seed packet type, and it can then call a function which sets the seed for the cryptography using the final piece of data in the stream.
02/13/2011 20:53 Mr_PoP#11
Quote:
Originally Posted by unknownone View Post
Because that's what the client expects to receive. The particular pieces of data are required in order to the client to be able to interpret the data you are sending.

For starters, the length field of the packet is required in TCP (stream based) communication, because the client must be able to recognise where a particular piece of information starts and ends. If you call send 5 times on a server, that doesn't necessarily mean that the client will need to call recv 5 times to recv those 5 pieces of data. It may only need to call it once, or it may need to call it 10 times. It depends on the load on the network, it cannot be decided beforehand where each send was sent in the stream. So we add a length to each "send" so that the receiver can interpret the data and decide where each piece of sent information begins and ends.

As for the type - This is a primitive that decides what the receiver should do with the data. There's lots of different pieces of data you can send that do different functions (for example, one might contain login information, another might contain some chat information). The type primitive just identifies each piece of information so that it can be mapped to a function that is to be performed on the payload. (In this case, is the seed).

So if you send data as described. The client will first read the length, to determine when to stop receiving for this particular piece of data. It will then read the type, and see it is the Seed packet type, and it can then call a function which sets the seed for the cryptography using the final piece of data in the stream.
man thanks u made my day xD , really thnx :) , onther question :P why is the client crashs when i use sConnect?
02/13/2011 20:55 unknownone#12
Most likely because you are sending incorrectly formed data which the client doesn't expect, and it is unable to recover from the error, so it just shuts down.
02/13/2011 21:01 Mr_PoP#13
Quote:
Originally Posted by unknownone View Post
Most likely because you are sending incorrectly formed data which the client doesn't expect, and it is unable to recover from the error, so it just shuts down.
i did the same thing u told me :-s

Code:
packetSeed * packet = new packetSeed();
			packet->Length = 8;
			packet->Type = 0x423;
			packet->Seed = 74185296;
			send(sConnect, (char*)packet, sizeof(packetSeed), 0);
ummmmm....
02/13/2011 21:08 unknownone#14
Difficult for me to determine with so little information. Firstlt, try checking the data is correctly formed by printing it out as a stream.

output_hex(cout, (char*)packet, packet->length);

It should look something like

08 00 23 04 50 FA 6B 04

You need to encrypt it before sending though.
02/14/2011 03:05 QuickCo#15
Maybe because he's using 127.0.0.1, the client reject Localhost.