26
\$\begingroup\$

So I've decided I want to keep pirated copies of my XNA game from accessing official game servers (which are moderated, so people who paid for the game will get the best experience) by disconnecting clients with wrong or generated, duplicate or banned CD keys (or serial numbers, since the game is digital and there are no CDs whatsoever).

How do I get that serial number protection system into my game (both clients and main authentication server), so it's not easily hackable?


Note that I have no experience with making good protection of that kind for software.

I've never done this before, but I understand the basics. I see why I can't do key checks on client, so it's fine by me to use login/pass authentication with one-time key entry.

Currently, the goal of this protection is to keep potential cheaters and disruptively behaving players out of official servers. Anyone can play on private servers with or without a key, but the chance they may get undesirable experience with other players is greater. I guess it's easy enough on purchasing players, since they have to be online to play on official servers.

Because hacking the client is too easy, I'm going to protect only the initial registration (and possibly server-side authentication) procedures, so nobody can steal the keys while they're being transfered.


See also:

How should multiplayer games handle authentication?

\$\endgroup\$
11
  • \$\begingroup\$ If somebody downvotes, I expect at least a comment about what is wrong with the question. Guys, really, I want my question to be good and help more people than just me. \$\endgroup\$ Commented Feb 10, 2013 at 11:17
  • 4
    \$\begingroup\$ I'm guessing it was an automatic reaction to adding DRM. This type isn't particularly bad, but a lot of us have bad experiences with it - such as when Spore bricked my Windows install. \$\endgroup\$
    – Izkata
    Commented Feb 10, 2013 at 16:30
  • \$\begingroup\$ Instead of a CD key have you considered a MMO-like/Minecraft-like approach of requiring a username/password to log on and using that to authenticate users? \$\endgroup\$
    – Tetrad
    Commented Feb 11, 2013 at 17:37
  • 4
    \$\begingroup\$ Wanting DRM on a .NET app!? This will fail eventually with tools like Reflector. Take a look at Terraria. Development has stopped due to piracy (and a lot of revenue...). I like @Tetrad's authentication based idea as it prevents people from just having to patch the validation function. Keep all data on your server and when their login is successful, feed them their data. If you keep the data locally, then they can just patch out the authentication function. \$\endgroup\$
    – user20618
    Commented Feb 13, 2013 at 19:29
  • 2
    \$\begingroup\$ @Anko that was a reference to the famous quote "We require more minerals". And I do mean facts and expertise. Maybe even detail. I wouldn't know when an important problem has had enough attention, it just felt like there is something to add, and site's visitors might find this subject interesting (and possibly become new users), so I raised the bounty. \$\endgroup\$ Commented May 12, 2013 at 15:56

3 Answers 3

25
\$\begingroup\$

Basically, you have three requirements:

  1. it should not be easy to use the same key for multiple client instances,
  2. it should not be easy to generate new valid keys, and
  3. it should not be easy to steal the key of a legitimate client.

The first part should be pretty straightforward: just don't let two players log into the same server with the same key at the same time. You can also have the servers exchange information about logged-in users, or contact a shared authetication server, so that even using the same key for different players on different servers at the same time will fail. You will also probably want to look for suspicious patterns of key use and, if you determine that a key has been leaked, add it to a list of banned keys.


For the second part, one way is to simply maintain a database of all valid issued keys. As long as the keys are long enough (say, 128 bits or more) and chosen randomly (using a secure RNG), the odds of anyone managing to guess a valid key are essentially zero. (Even much shorter keys can be safe if you use some kind of rate limiting on failed login attempts to stop attempts to find valid keys by brute force.)

Alternatively, you can generate keys by taking any unique identifier and adding a message authentication code (such as HMAC), calculated using a secret master key, to it. Again, as long as the MAC is long enough, the odds of anyone who doesn't know the master key being able to guess a valid MAC for any ID is negligible. One advantage of this method, besides removing the need for a key database, is that the identifier can be any unique string, and can encode information about the client the key was issued for.

One problem with using MACs is that the official game servers (or at least the authentication server) need to know the master key in order to verify the MAC, which means that, if the servers are hacked, the master key might be leaked. One way to mitigate this risk could be to compute several MACs for each ID, using different master keys, but only store one of the master keys on the game servers. That way, if that master key is ever leaked and used to generate fake IDs, you can revoke it and switch to another master key. Alternatively, you could replace the MACs with digital signatures, which can be verified using only the public half of the master key.


For the third part, one approach is to make sure that the client won't send its key to anyone without verifying that the recipient really is a legitimate official server. For example, you could use SSL/TLS (or DTLS) for the login process, issue custom certificates for your game servers and only have the client trust certificates issued by you. Conveniently, using TLS will also protect the client keys (and any other authetication data) from eavesdroppers e.g. on public WLANs.

Unfortunately, this approach won't let third-party servers verify client keys even if they want to. You could work around this by setting up an official authentication server that third-party game servers can make use of, e.g. by having the client log in to the authentication server and receive a random one-time token which they can use to log into the game server (which then submits the token to the authentication server to verify it).

Alternatively, you could issue actual client certificates, or something like them, to your clients. You could either use an existing protocol (like TLS) that supports client certificate authentication (recommended) or implement your own, e.g. like this:

  • The client certificate consists of an arbitrary ID string, a public/private key pair and a digital signature of the ID and the public key using the master key.
  • To log in, the client sends their ID, public key and signature. The server replies with a unique challenge string (preferably including a server ID and a timestamp, which the client should verify), which the client signs with the private key (to prove that they know the key) and sends the signature to the server.
  • The server checks both signatures, proving that the ID + public key form a legitimate client key (since they were signed with the master key) and that the client key actually belongs to the client (since the client could sign the server's challenge with the private key).

(This protocol could be further simplified by having the client generate the "challenge", consisting of a server ID and a timestamp, and sign it. Of course, then the server needs to verify that the ID and timestamp are valid. Also note that this simple protocol, on its own, won't stop a middleman attacker from being able to hijack the client's session, although it will prevent them from obtaining the client's private key needed for future logins.)

\$\endgroup\$
3
  • 2
    \$\begingroup\$ One minor point--while a totally random key provides the maximum keyspace (and is perfectly workable if you're validating against a database of issued keys) it's not user-friendly. Put some validation into the key itself so that most mistypes are caught before you try to hit the server. \$\endgroup\$ Commented May 11, 2013 at 17:59
  • \$\begingroup\$ I do think, @LorenPechtel has a strong point there about user-friendliness of the key, And the paid user accidentally typing and sending a 'wrongly typed/spelling mistake' (typo) key to the server is always possible. \$\endgroup\$
    – Vishnu
    Commented May 17, 2013 at 3:59
  • \$\begingroup\$ @Vishnu I know as a user who types in keys I would much prefer to have some check info per group even if that meant typing a longer key. \$\endgroup\$ Commented May 17, 2013 at 23:41
16
\$\begingroup\$

There's no 100% savety, but you could start with a rather simple approach:

  • You'll need some way to verify generated keys, for example included checksums. Of course, this must not be too easy to figure out.

  • Optional (but recommended) there'd be a server side database verifying the keys with a database of all given out keys so you can't generate keys, even if you happen to have the algorithm (let's ignore bruteforcing it).

From there on you can have two different approaches, but in either way something is very important:

  • Don't verify the key on the client side. This is very important, because it's actually rather easy to decompile stuff written in .net/XNA. If you have to ask for the key or pass it (login or registration) hash the key (with an added salt etc.) and send it to the server.

As for the actual paths:

  • Require the hashed key (see above) to be sent during the authentication/login procedure.

  • As an alternative (IMO the better one, although many don't like this sort of "DRM"): Don't use the key in the client at all. Instead, require the user logging in to an account and require a valid CD key (this requires the database mentioned above) to create accounts. This is how modern games, e.g. any pay-to-play MMORPG handles this.

Personally, I'd go with the account approach due to a simple reason: In the end, you can't keep people from stealing CD keys (bruteforcing, reverse engineering or scamming). As such People could just create a new key to continue playing or to lock out others from the game. With account bound keys noone is able to do anything with a key that is already in use. In case someone bought a key someone else generated, you could still transfer the account ownership assuming there's sufficient proof of this.

\$\endgroup\$
3
  • 2
    \$\begingroup\$ Instead of standard checksums, you should use a cryptographically secure hashing algorithm. You can keep the private key on the server and give the client the public key and then you know that without access to the server the system is secure. \$\endgroup\$
    – Adam
    Commented Feb 10, 2013 at 17:02
  • \$\begingroup\$ @Adam: Using a cryptographically secure hashing algorithm will ensure attackers cannot generate valid keys, but the problem is equally unsolvable by the authority in charge of handing out legitimate keys. While indeed a simple checksum isn't very secure, one-way functions are not viable in this context. \$\endgroup\$ Commented Feb 12, 2013 at 11:36
  • \$\begingroup\$ Well, you can combine both, e.g. making the first part of the key a random combination of characters and the second half the hash. Anyone selling the game couldn't use a keygen anyway (unless there's some way to ensure no collisions/conflicts happening, like a "vendor id" as part of the key). \$\endgroup\$
    – Mario
    Commented Feb 12, 2013 at 19:54
1
\$\begingroup\$

Pangea Software -creator of several Mac games- has written a topic about copy protection in their (now free) game development book. The book also explains how to deal with pirated keys and other hacks people use. The book has a focus on development of Mac games, but the ideas might still be useful for other platforms. Included with the book is source code for each chapter, part of the download below. There's also source code (written in C) included related to copy protection.

The book can be downloaded here.

\$\endgroup\$
2
  • \$\begingroup\$ I couldn't find anything useful in that books. \$\endgroup\$ Commented Feb 11, 2013 at 23:14
  • \$\begingroup\$ Personally I though chapter 16 had some nice tips, but YMMV. \$\endgroup\$ Commented Feb 12, 2013 at 0:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .