GTS protocol: Difference between revisions

From ProjectPokemon Wiki
Jump to navigation Jump to search
(→‎Searching: length of sent data)
(→‎Protocol: add encryption details)
Line 19: Line 19:
===Challenge/response===
===Challenge/response===


Before each "real" request, the game sends a request of the form <code><var>page</var>.asp?pid=<var>pid</var></code> and the server responds with a 32-byte challenge token. The game computes <code>sha1("sAdeqWo3voLeC5r16DYv" + token)</code> and uses that as the <var>hash</var> value which it sends to the server. The <var>data</var> parameter is encrypted with an unknown algorithm.
Before each "real" request, the game sends a request of the form <code><var>page</var>.asp?pid=<var>pid</var></code> and the server responds with a 32-byte challenge token. The game computes <code>sha1("sAdeqWo3voLeC5r16DYv" + token)</code> and uses that as the <var>hash</var> value which it sends to the server. The <var>data</var> parameter is encrypted, as explained further down.


That is, each request looks like the following:
That is, each request looks like the following:
Line 28: Line 28:
# Server responds with payload
# Server responds with payload


Unfortunately, this means that the exact details of the game's requests are currently not known.
The exact details of the game's requests are not currently known, but we are working on it!
 
===Checksum===
 
A 32-bit checksum of the data is used as the key for the encryption. The checksum is simply the sum of every byte of the data.
 
The first 4 bytes of the sent data are the checksum, <code>xor</code>ed with <code>0x4a3b2c1d</code>, and sent in network byte order (big-endian).
 
===Encryption===
 
The data sent to the server is encrypted with a [http://en.wikipedia.org/wiki/Stream_cipher stream cipher], and [http://en.wikipedia.org/wiki/Base64#URL_applications urlsafe-base64]-encoded.
 
This encryption algorithm, like others used in the game, uses a [http://en.wikipedia.org/wiki/Linear_congruential_generator Linear Congruential Generator] (not a very strong choice). The multiplicative constant is <code>0x45</code>, and the additive constant is <code>0x1111</code>. It appears that the game uses a signed dword to store the seed, which doesn't really matter; it shouldn't affect anything. (It means that the modulus is effectively <code>0x80000000</code>.)
 
GRNG[n+1] = (GRNG[n] * 0x45 + 0x1111) & 0x7fffffff
 
The GRNG is seeded with the <var>checksum</var>, like so:
 
GRNG[0] = <var>checksum</var> | (<var>checksum</var> << 16)
 
The keystream is composed of the lower byte of the high word of successive GRNG values.
 
keystream[n] = (GRNG[n] >> 16) & 0xff
 
<code>Xor</code> the keystream with the plaintext to get the ciphertext. <code>Xor</code> the keystream with the ciphertext to get the plaintext.


==Conversation==
==Conversation==

Revision as of 09:37, 15 April 2010

The following is wild conjecture based on LordLandon's sendpkm.py.

Communication with the GTS is done over regular HTTP with http://gamestats2.gs.nintendowifi.net/. The same protocol is used for all five Gen IV games.

HTTP headers

The games don't seem to care about these at all. The GTS sends back a bunch of boilerplate response headers, but the game happily accepts a response with only a Content-Length.

Protocol

All requests to the server are GET requests of the form page.asp?pid=pid&hash=hash&data=data.

pid

The pid is an unsigned 32-bit integer that appears to uniquely identify a game cartridge. When the pid is obtained and whether the pid has any relation to the Pal Pad friend code are unknown.

For the mathematically inclined: Eevee's Platinum pid is 192615460 (0x0b7b1424) and his Pal Pad code is 0904 2026 4621.

Challenge/response

Before each "real" request, the game sends a request of the form page.asp?pid=pid and the server responds with a 32-byte challenge token. The game computes sha1("sAdeqWo3voLeC5r16DYv" + token) and uses that as the hash value which it sends to the server. The data parameter is encrypted, as explained further down.

That is, each request looks like the following:

  1. Game requests GET /pokemondpds/page.asp?pid=pid
  2. Server responds with token
  3. Game requests GET /pokemondpds/page.asp?pid=pid&hash=sha1(...)&data=data
  4. Server responds with payload

The exact details of the game's requests are not currently known, but we are working on it!

Checksum

A 32-bit checksum of the data is used as the key for the encryption. The checksum is simply the sum of every byte of the data.

The first 4 bytes of the sent data are the checksum, xored with 0x4a3b2c1d, and sent in network byte order (big-endian).

Encryption

The data sent to the server is encrypted with a stream cipher, and urlsafe-base64-encoded.

This encryption algorithm, like others used in the game, uses a Linear Congruential Generator (not a very strong choice). The multiplicative constant is 0x45, and the additive constant is 0x1111. It appears that the game uses a signed dword to store the seed, which doesn't really matter; it shouldn't affect anything. (It means that the modulus is effectively 0x80000000.)

GRNG[n+1] = (GRNG[n] * 0x45 + 0x1111) & 0x7fffffff

The GRNG is seeded with the checksum, like so:

GRNG[0] = checksum | (checksum << 16)

The keystream is composed of the lower byte of the high word of successive GRNG values.

keystream[n] = (GRNG[n] >> 16) & 0xff

Xor the keystream with the plaintext to get the ciphertext. Xor the keystream with the ciphertext to get the plaintext.

Conversation

The first request the game makes is to /pokemondpds/worldexchange/info.asp. The server responds with 0x0001.

Platinum, Heart Gold, and Soul Silver will then make a request to /pokemondpds/common/setProfile.asp. The server responds with eight NULs (0x00000000 0x00000000).

After the above step(s) or performing any of the tasks below other than searching, the game makes a request to /pokemondpds/worldexchange/result.asp. If the game has had a Pokémon sent to it (via a successful trade?), the server responds with the entire encrypted Pokémon save struct. If there is a Pokémon deposited in the GTS, it responds with 0x0004. Otherwise, it responds with 0x0005.

Receiving a Pokémon

If the game receives a Pokémon from a successful trade as a response from result.asp, it next requests /pokemondpds/worldexchange/delete.asp. The server responds with 0x0001.

A note on sendpkm.py

After doing the above, some Platinum, Heart Gold, and Soul Silver games will report a communication error and dump the player back to the title screen. The Pokémon is still successfully received. At least one person with HG/SS has received a Pokémon from a fake server without getting the error, and Diamond/Pearl have never been reported to have the problem. It's possible that the server should respond with something other than 0x0001.

Depositing a Pokémon

Pokémon are offered on the GTS by requesting /pokemondpds/worldexchange/post.asp. The sent data is 300 bytes long, and includes the Pokémon struct.

The game then saves. After the save is complete, it issues a request to /pokemondpds/worldexchange/post_finish.asp.

Retrieving the deposited Pokémon

Checking on the deposited Pokémon is apparently done by /pokemondpds/worldexchange/get.asp. The response appears to be a Pokémon save struct.

Retrieving the deposited Pokémon is done by /pokemondpds/worldexchange/return.asp. The response is merely 0x0001; the actual Pokémon data is taken from the get.asp request.

Searching

Searching is done through /pokemondpds/worldexchange/search.asp. The sent data is either 15 or 16 bytes long.

The server responds with a full 292-byte Pokémon struct for each result. If there are n results, the response will be 292 * n bytes long. If there are no results, the server will give an empty response (0 bytes).

Pokémon struct

The Pokémon data for the GTS is 292 bytes—56 bytes larger than a party Pokémon struct. The extra 56 bytes are GTS-specific data, such as the player's name & country, and what Pokémon they are requesting.

They are as follows:

0x00-0x01 Current Pokémon
0x02      Gender          1=male; 2=female; 3=either/neither
0x03      Level
0x04-0x05 Requested Pokémon
0x06      Gender
0x07      Min level
0x08      Max level
0x09      always 0?
0x10      sometimes 1, sometimes 0
0x0B      always 0?
0x0C-0x0D Year deposited
0x0E      Month dep'd
0x0F      Day dep'd
0x10      Hour dep'd
0x11      Minute dep'd
0x12      Second depd'd
0x13      always 0?
0x14-0x1a Another timestamp. Time traded away?
0x1b      always 0?
0x1c-0x1f pid - also 0x4c in the sav
0x20-0x2F OT Name
0x30-0x31 OT ID
0x32      Country
0x33      City
0x34-0x37 Unknown