I have three participants:
- A client A in possession of the public key Kpub
- A login server S in possession of the private key Kpriv
- Game servers B (B1, B2 etc)
- S and all B may share a finite number of secrets before, but not after the exchange. This is basically a scalability measure. If S would need to send data to B in order to create a key for A, then that makes scalability harder.
- A and B should not use asymmetric key exchange, to reduce CPU impact on game servers.
The current scheme works roughly like this:
Client A, Login Server S, Game Server B
(1) A → S : { Na, A }Kpub
Ksa ← { Na, Ns, A, Saltenc }PBKDF2
Ksasign ← { Na, Ns, A, Saltsign }PBKDF2
M ← IV || HMAC(IV, { Na, A, Ttimestamp }Ksb)Ksbsign || { Na, A, Ttimestamp }Ksb
(2) S ➝ A : { Ns, IV, HMAC(IV, { Ns, M }Ksa)Ksasign, { Ns, M }Ksa }
(3) A ➝ B : { N'a, M }
(4) B ➝ A : { Nb }
Kab ← { Na, N'a Nb, Saltenc }PBKDF2
Kabsign ← { Na, N'a Nb, Saltsign }PBKDF2
Encryption proceeds using Kab, signing each with Kabsign and keeping a running counter with each packet.
I'm aware of some weaknesses in this as it is written which I intend to fix, but you should get the general idea of what I'm doing:
- Client A requests an encrypted packet containing it's nonce Na securely from S.
- S returns the packet encrypted packet in a way that A can assure the packet is from S.
- Client A gives the packet in the clear to B (since no one but B or S can decrypt it), who unpacks the nonce and can create a shared key Kab. This shared key is then used for the remaining communication, such as authenticating or registering A. (Of course, there are nonces thrown in, so each new request for a Kab will produce new keys)
So this is basically just for ensuring confidentiality of the channel between A and B.
The nice thing is that if the connection is dropped or logged out, then A can use M again for new connections to B without keys being repeated.
Now, given the difficulty getting a protocol right, it would be awesome to use a well-known vetted protocol for this.
Does anyone know of an alternative that works in a similar manner that I could replace it with?
EDIT:
The aim here is exchange keys in order to set up a secure channel between A and B. This is because at this point A might not be registered at B, so will need a way to register securely without anyone eavesdropping on that registration.
This is why the Kerberos model doesn't work - A might be entirely unknown to S and B.
I'm seeing the following possible threats I want to avoid:
- Someone eavesdrops on A's registration and is then able to login as A.
- Someone eavesdrops on A's login and is then able to play as A.
- Someone eavesdrops on A's login and is able to login as A by replaying the first messages. This will cause A to get disconnected even if the attacker can't continue the conversation.
- If, due to network issues, many clients simultaneously disconnect and then reconnect, the reconnect is sufficiently costly that B is unable to process all connects.
- Someone mounts a man-in-the-middle attack and is able to randomly change what A does.
- Someone redirects traffic to a server B' without A being aware of it.
- A DDoS acting like (4) should only affect the server attacked.
Or more succinctly:
- A can safely play - any covert manipulation will be detected by client and/or server and no-one can steal A's credentials without accessing the data in the client directly.
- The server topology is not sensitive to DoS / DDoS.