7
$\begingroup$

I am working on a multiplayer game.

I have a central server which handles all data transmission and coordinates all games. Clients which involved in a single session send requests to do actions to the server, those actions are checked and the consequences are pushed to all clients.

I am looking for a way for the server to confirm whether the request came from authorised client (a specific player).

I originally planned to use RSA, but it's too computationally expensive, and is an overkill since I don't need really need request data encrypted.

What should I do/use for this purpose?

$\endgroup$
9
  • $\begingroup$ Can you use MACs? ​ ​ $\endgroup$
    – user991
    Dec 17, 2015 at 8:47
  • 3
    $\begingroup$ @RickyDemer Does MAC not require both server and client to share a secret key? This requires me to send the secret key over the internet which, if intercepted can not only allow forgery, but can also block authorised client from communicating with the server. $\endgroup$
    – Mirac7
    Dec 17, 2015 at 9:00
  • 2
    $\begingroup$ You'd use a handshake based on asymmetric crypto and then a MAC for all further messages. I strongly recommend using existing protocols, like TLS, DTLS or CurveCP for this. $\endgroup$ Dec 17, 2015 at 9:25
  • 3
    $\begingroup$ Your first action shall be to define what "who" is (in "efficiently confirm who sent the request to the server"), and what credential it can have that other entities have not. In "a multiplayer game" that depends a lot on the platfrom, and how the game is distributed. This is off-topic, I'm afraid; perhaps security.SE ? $\;$Remark: with RSA used to "confirm who sent the request to the server", you would use RSA signature, and data would not be encrypted. You are right that this is compute-intensive, ECDSA would be less. $\endgroup$
    – fgrieu
    Dec 17, 2015 at 9:31
  • 1
    $\begingroup$ What is your adversary model? Are you assuming your adversary will reverse engineer your software to attempt to cheat and send incorrect identifiers? Are you worried that your adversary will spoof other clients or hack them and get their secrets and then spoof them? $\endgroup$
    – mikeazo
    Dec 17, 2015 at 16:20

2 Answers 2

1
$\begingroup$

Traditionally, one would just use an implementation of DTLS and some form of challenge-response player authentication.

$\endgroup$
3
  • $\begingroup$ If RSA is 'too expensive' (whatever that means), than how is DTLS any better? $\endgroup$
    – poncho
    Jul 31, 2016 at 16:37
  • 1
    $\begingroup$ @poncho There is a difference though about a single authentication using RSA (or any other asymmetric cryptographic primitive) and each packet being signed. It's unclear if this is acceptable to Mirac7, but if I look at the comments, then it seems it is. $\endgroup$
    – Maarten Bodewes
    Jul 31, 2016 at 16:45
  • $\begingroup$ @poncho because I'm suggesting not using RSA encryption, but something more like TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 $\endgroup$
    – MickLH
    Jul 31, 2016 at 17:30
1
$\begingroup$

You're right, using RSA (or other public-key schemes) to sign and/or encrypt each message between the client and the server would be impractically slow, not to mention wasteful of bandwidth.

The standard solution to this problem is to use public-key crypto only to set up a shared secret key between the client and the server, and thereafter use a symmetric authenticated encryption for all communication between the client and the server.

Some methods of setting up the shared secret key also authenticate the client as part of the process. However, even if they do not, once you've set up an encrypted secure channel between the client and the server, it's easy enough for the client to prove its credentials over the encrypted channel without any eavesdroppers being able to observe the process.

This is basically what SSL / TLS does whenever you connect to a website over HTTPS, and indeed you could simply use a TLS library in your client and your server to establish a secure connection between them. Note that plain TLS is a stream encryption protocol usually used over TCP/IP; if your game's client-server protocol is packet-based and runs on top of UDP, you may want to pick a library that also supports DTLS. Of course, this would mean setting up TLS certificates for your servers, probably signed by your own private CA that your client code is configured to trust; all that is something of a chore, but still a lot easier and safer than writing your own crypto from scratch.


If you do insist on rolling your own crypto, or just want to get an idea of what it would involve, here's a quick sketch of something that should more or less meet your needs:

  • Each of your servers has an RSA public/private key pair. Each server also has a signature of its public RSA key, signed by your personal master RSA signing key. Each game client has the public half of your master key, allowing it to verify the authenticity of the server keys.

    (The servers should not store the master key itself, since you don't want the master key to be leaked if a server is hacked. Also, the signed server keys should include a timestamp, and the client should not accept any signature whose timestamp is too old, so that any compromised server keys will eventually expire.)

  • When the client connects to the server, the server replies with their signed public RSA key. The client verifies the signature (and the timestamp), and if it's valid, generates a random AES key, encrypts it with the server's public RSA key, and sends it to the server.

  • The server decrypts the AES key sent by the client; after this, all further messages exchanged by the client and the server are encrypted and authenticated using AES-SIV. (All messages should also include a sequential message number and an indicator of which way they were sent, to prevent replay attacks.)

Note that the basic scheme above does not authenticate the client to the server in any way. If this is required, one simple solution would be to give each client its own RSA signing key, and having the servers store the corresponding public keys. After establishing a secure connection, the server can then send a randomly chosen challenge string to the client, and ask for the client to verify its identity (i.e. knowledge of the correct client's private RSA key) by sending back an RSA-signed response that includes the challenge string.

Other possible client authentication methods include e.g. SRP, or even just having the client send a password to the server over the encrypted channel. Note that the latter method should preferably be avoided (despite its ubiquity on the web) for the simple reason that it allows a compromised server to record client passwords. Schemes like SRP or even the basic RSA challenge-response scheme described above, where the server never actually sees the client's private key or password, are more secure in this respect.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.