Getting blowfish key and using the algorithm

01/05/2011 22:39 sjaakie100#1
Good evening:)

I am still busy with the packets of silkroad and I'm now trying to understand on how to decrypt the packets but I'm having some problems with it.
I read drew benton's artikel about the silkroad security but I still don't know on which blowfish key is used to decrypt the packets.
let's say these four packets are the first 4
Code:
S -> C
00000   25 00 00 50 00 00 0e d2  a9 27 80 2d c3 23 6c f6    %..P.....'.-.#l.
00016   00 00 00 62 00 00 00 8d  ac fe 38 3d d0 9c ef 67    ...b......8=...g
00032   f7 bc 46 6b 73 d0 70 e5  1d b8 56                   ..Fks.p...V

C -> S
00000   0c 00 00 50 ec cb 98 d5  9c 3e 7d 03 94 b0 9c 60    ...P.....>}....`
00016   92 56                                               .V

S -> C
00000   09 00 00 50 00 00 10 4c  f8 b7 1d e2 79 3c b5       ...P...L....y<.

C -> S
00000   00 00 00 90 80 8e                                   ......
I know that the first 2 bytes are the size of the packet data the 2 after those the opcode and the 2 after the opcode the security bytes. But in which packet is the actual blowfish key which is used to encrypt and decrypt some packets?
is it this one: d2 a9 27 80 2d c3 23 6c of the first packet starting with the 7th byte or is it the one in the 3rd packet also beginning at the 7th byte? and i read something about the key which is also encrypted or something like that is that true?

Thank you:)
01/05/2011 22:42 bootdisk#2
bot90210's guide would be a great addition to your current inquiry.
Also, by seeing drew's source attached to that guide you will get what you want to know since it goes step by step to get that.
01/05/2011 22:59 pushedx#3
There is a "handshake process" that runs that comes up with the final Blowfish keys used. Grab my [Only registered and activated users can see links. Click Here To Register...] project. It contains the latest version of my security code. Once you get it, you will want to start looking over the silkroad_security.h / silkroad_security.cpp files.

Lines 458 - 522 of silkroad_security.cpp contain the relevant code you are asking about.
Code:
			if( packet_opcode != 0x5000 )
			{
				throw( std::runtime_error( "[SilkroadSecurityData::Handshake] Received an illogical handshake packet (programmer error)." ) );
			}

			uint8_t flag = packet_data.Read< uint8_t >();

			TFlags * flags = (TFlags *)&flag;

			if( m_security_flag == 0 )
			{
				m_security_flag = flag;
			}

			if( flags->blowfish )
			{
				m_initial_blowfish_key = packet_data.Read< uint64_t >();
				m_blowfish.Initialize( &m_initial_blowfish_key, sizeof( m_initial_blowfish_key ) );
			}

			if( flags->security_bytes )
			{
				m_seed_count = packet_data.Read< uint32_t >();
				m_crc_seed = packet_data.Read< uint32_t >();
				SetupCountByte( m_seed_count );
			}

			if( flags->handshake )
			{
				m_handshake_blowfish_key = packet_data.Read< uint64_t >();
				m_value_g = packet_data.Read< uint32_t >();
				m_value_p = packet_data.Read< uint32_t >();
				m_value_A = packet_data.Read< uint32_t >();

				m_value_x = static_cast< uint32_t >( rng() & 0x7FFFFFFF );

				m_value_B = G_pow_X_mod_P( m_value_p, m_value_x, m_value_g );
				m_value_K = G_pow_X_mod_P( m_value_p, m_value_x, m_value_A );

				uint64_t key_array = MAKELONGLONG_( m_value_A, m_value_B );
				KeyTransformValue( key_array, m_value_K, LOBYTE_( LOWORD_( m_value_K ) ) & 0x03 );
				m_blowfish.Initialize( &key_array, 8 );

				m_client_key = MAKELONGLONG_( m_value_B, m_value_A );
				KeyTransformValue( m_client_key, m_value_K, LOBYTE_( LOWORD_( m_value_B ) ) & 0x07 );
				m_blowfish.Encode( &m_client_key, 8, &m_client_key, 8 );
			}

			if( flags->handshake_response )
			{
				m_challenge_key = packet_data.Read< uint64_t >();

				uint64_t expected_challenge_key = MAKELONGLONG_( m_value_A, m_value_B );
				KeyTransformValue( expected_challenge_key, m_value_K, LOBYTE_( LOWORD_( m_value_A ) ) & 0x07 );
				m_blowfish.Encode( &expected_challenge_key, 8, &expected_challenge_key, 8 );

				if( m_challenge_key != expected_challenge_key )
				{
					throw( std::runtime_error( "[SilkroadSecurityData::Handshake] Server signature error." ) );
				}

				KeyTransformValue( m_handshake_blowfish_key, m_value_K, 0x3 );
				m_blowfish.Initialize( &m_handshake_blowfish_key, 8 );
			}
Depending on the security mode ( the first data byte of the 0x5000 packet, 0x0E ) you have to read specific parts of the packet in order. That security flag is really just a bitstruct of different fields, so the following struct explans that:
Code:
#pragma pack( push, 1 )
struct TFlags
{
	uint8_t none : 1;
	uint8_t blowfish : 1;
	uint8_t security_bytes : 1;
	uint8_t handshake : 1;
	uint8_t handshake_response : 1;
	uint8_t _6 : 1;
	uint8_t _7 : 1;
	uint8_t _8 : 1;
};
#pragma pack( pop )
When the security flag is 0x0E and it's cast to that struct, you end up getting the blowfish, security_bytes, and handshake fields set. As a result, if you trace through the previously posted code, the m_initial_blowfish_key field is read first, then the m_seed_count and m_crc_seed fields, followed by the m_handshake_blowfish_key, m_value_g, m_value_p, and m_value_A fields.

Since the Handshake flag is set, the initial blowfish key sent from the Blowfish flag is overwritten by the one generated in the Handshake logic. If no Handshake flag was sent, then the initial blowfish key would be used instead. After the Handshake process starts, the second security packet you get, with data flag 0x10, has the handshake_response field set, so that logic executes. In that portion of the code, a the final Blowfish key is calculated and used.

To better understand the whole process, take a look at the DH Key Exchange protocol, which is what Silkroad uses. The Blowfish is a little-endian implementation, so it is not compatible as-is with standard Blowfish.

So it can be a complicated process to understand first, but you can spend some time looking through the code and following the logic to see how it all works together.
01/06/2011 19:11 sjaakie100#4
Wow thank you guys very much for your answer. A great explenation drew. I downloaded your project and it's really really usefull. I think I'll be able to understand the handshake process after viewing your code and trying some stuff:)
I've one question. I see that you generate all those security bytes and responses in your projects but is it possible to have something like winpcap which just sniffs the packets and extracts the keys to decrypt the packets after those or do you create a key or something during the handshake process which is only available in the client?

Thank you:)

By the way, I'm sorry for my english.

EDIT:

I'm sorry but this is way offtopic but to pushedx I used your edxSilkroadLoader5 but I'm not getting some packets with the packet parser enabled. for example the packet of the server list doesn't show up.
01/06/2011 22:49 pushedx#5
Quote:
Originally Posted by sjaakie100 View Post
I've one question. I see that you generate all those security bytes and responses in your projects but is it possible to have something like winpcap which just sniffs the packets and extracts the keys to decrypt the packets after those or do you create a key or something during the handshake process which is only available in the client?
Nope, given the packets from both sides in the middle, you cannot deduce enough information to decipher the entire handshake. Take a look at this. The only way it'd be possible is if you were to make the client use a predefined non-random value for their 'a', which is what my Patch Seed option does in the loader. That was from before I had done the entire process and it was the only way it'd work.

Quote:
I'm sorry but this is way offtopic but to pushedx I used your edxSilkroadLoader5 but I'm not getting some packets with the packet parser enabled. for example the packet of the server list doesn't show up.
The packet parser is just for AgentServer packets. The client uses a different manual style parsing for the GatewayServer packets. Check out this topic, [Only registered and activated users can see links. Click Here To Register...] by lesderid for some specific information on those packets. For more information on my packet parsing and building parsing logic, have a look at: #5 and #6 of my [Only registered and activated users can see links. Click Here To Register...].

Also with the packet parser, some packets are "spanned" across many different individual packets and then rebuilt in another function. So you won't see every single packet being parsed, only the packets the client has to physically parse. For the spanned packets, the opcode won't be correct. That tool is just to show how the client parses 99% of the packets, you still have to do a little extra work for the 1% it doesn't do. I.e., it'll read some entire buffers then subparse manually rather than use the packet interface. For stuff like that you'll have to do yourself.

For development, the best thing to do is run the auto-parser + proxy (like [Only registered and activated users can see links. Click Here To Register...]) so you get the full packet stream in the proxy + tools to inject and analyze as well as the auto parser to see how most packets are actually parsed. That toolset should give you almost everything you need, but some client reversing will still be needed for some packets anyways.
01/16/2011 19:56 viky909#6
Great Work all and special thanks for pushedx for his tools :D

I want to say something :-

I follow some guides from you and now trying to understand the silkroad packets , but

Like login action : get some packets from server and client
But if somehow I can inject this packets ; it work fine too ?!

I mean is this how bots use to auto log in ?!
and is this the same way for sending packets for moving and killing mobs ?!

"Im trying to make simple bot for personal Use .However, Sniffing packet work only on private server like Srevolution from Xcoding team as isro now is crowded ! "

If so ; should I decrypt packets and send them to client or just send them encrypted ?
and how to do that [Simple mode please ].
Need little help on those questions :d

[Sorry for my bad English]
03/14/2011 20:56 sjaakie100#7
Hi all,

I'm having a really hard time to understand the damn encryption I've digged in drew's code for many many hours but I still don't get how to logic works. I know that the blowfish key is encryption which needs to be decrypted with the initial blowfish key (if i'm correct) but the code from the silkroad article didn't worked cause when I sended the first packet from the cilent to the server I didn't get any response. And I don't get the latest silkroadsecurity.h and .cpp by drew benton. it looks like magic cause it's soo big.

is there a more easier way to just get the key from the packets so you don't have to generate the key's by yourself but to just sniff them from the packet?
03/15/2011 11:47 pushedx#8
The only "cheat" you can do is make the client use a fixed random seed, but you would still have to understand the entire client security process.

Try browsing through the [Only registered and activated users can see links. Click Here To Register...] version instead of the C++ version if it doesn't make much sense.

Basically, there are 3 main functions you need to look through:

1. SecurityAPI::Recv

Breaks up the TCP stream into logical packets first. Once you have logical packets, you can then process them.

So for you, first you need to understand how to break down the stream into packets. That's pretty simple, as you read two bytes and check the size. If the size is > 0x8000, then the packet is encrypted, if it's not, then it isn't. If the packet is encrypted, the payload size has to be % 8 (since that is what Blowfish requires) so you have to add 0 - 7 bytes to make the size % 8 (NOTE: The payload includes the 4 byte header for encrypted packets). If the packet is not encrypted, then the payload size is 4 (rest of the header) + the packet size. Once you know how many bytes of data you need, you just recv until you have them.

Now, you have raw 'packets' ready for processing.

2. SecurityAPI::Handshake

The logic that handles the entire security system. If the packet has an opcode of 0x5000 or 0x9000, it is part of the security system, so the Handshake function will process it. The packet format is dynamic depending on the mode. To see how the packet is generated, take a look at the SecurityAPI::GenerateSecurity function to understand the values. The client processes the packet the same way it is built, except that it reads rather than wrties.

3. SecurityAPI::FormatPacket

The logic for sending packets. For Client to Server packets, what goes on here simply depends on the security mode.

There's not much to understand about the encryption itself; it's just little-endian [Only registered and activated users can see links. Click Here To Register...]. What you are having trouble with is understanding the actual Handshake process.

To understand the handshake process better, read up on the Diffie–Hellman key exchange.

Once you understand the DH-KE algorithm, they just use a few custom functions (KeyTransformValue in the C# code) to scramble the data a little to prevent it from being 'trivial' to reimplement without digging through the client.

So basically it works like this:

1. Client connects to the server; server sends the initial security packet.

2. Client processes the security packet based on the mode (1st byte, look at my SecurityFlags structure) If:
blowfish - The initial blowfish key is read from the packet.
security_bytes - The base security bytes are read from the packet
handshake - The handshake values are read from the packet; a new blowfish key is used (read up on the DH-KE to understand why)

3. Client will send a response based on the security mode. Upon security acceptance, 0x9000 is finally sent and then regular packets begin (identify, 0x2001)

The logic isn't as complex as it might look at first. The reason there is so much code is because the security API handles literally everything for you, so all you have to do is use the API and not worry about anything else. Also, the server processing code is included so that adds quite a bit of extra code, but it is a complete solution. The Silkroad security supports multiple modes so additional processing has to be done to ensure all modes are supported. SRO is the only game I've ever seen that does this, so it is quite unique.

You can grab a more recent, but currently outdated C++ version [Only registered and activated users can see links. Click Here To Register...]. I'd still recommend going through the C# code as well if you are familiar with that language as it is the most recent version I have. If you look through say a really old copy like [Only registered and activated users can see links. Click Here To Register...], it works but there is noticeably more work and complications you have to deal with. My latest versions are designed around hiding all of that from the user.

Hope that helps!
03/16/2011 09:03 sjaakie100#9
Thank you so much:) I digged through your C# project and managed to get trough the handshake process:D I still don't really know how it exactly works but I will definitly read the Diffie hellman key exchange article. The most important thing for me was to get something working and once that's done I can test some things too see how it really works:)

Again thank you very much for your great explanations!:)
03/17/2011 19:49 sjaakie100#10
Just another quick question is the handshake process for the gameserver the same as the login server?
03/17/2011 22:58 InvincibleNoOB#11
Yes.