CD Key SDK
From GameSpy SDK
CD Key SDK
Overview
The GameSpy CDKey SDK is a simple toolkit designed to allow developers to add secure, server-based CD Key validation to their games. Server-based CD Key validation has proven to be the only widely successful method of combating piracy available today.
In server-based CD Key validation, a client sends its CD Key to the game server / host when it wants to join a multiplayer game. The server checks with a validation server on the backend to make sure that the CD Key is valid. If it isn't, the server refuses the connection. The validation server also ensures that no two players can use the same key at the same time. Of course the key is always encoded so that neither the server operator nor someone "sniffing" the connection can steal the CD Key.
Several other common anti-piracy methods are:
- Client-based CD Keys / Serial numbers
- Can easily be "cracked" and removed
- CD Check / CD anti-copy measures
- As long as the data on the disc can be read, it can be copied and the CD Check can be cracked
- Overburn / 80 minute CDs
- Recordable 80 minute CDs are now widely available, and CD emulators can often get around this protection as well
Server-based CD Key validation works because it is controlled completely by the server/host - a client cannot "crack" any part of their local code to give the correct response to the server without a valid CD Key. While server-based CD Key validation is not "perfect", any flaws that exist are in the implementation, not the concept.
Please note that server-based CD Key validation is only appropriate for a certain class of games. While the CD Keys can also be checked on the client side to help protect the single player game, they cannot add any greater amount of protection to the single player (non-Internet) portion of the game than a normal CD key check would. The only thing that server-based CD Key validation can do 100% effectively is prevent clients without valid keys from playing on public Internet servers. However, for games that are primarily multi-player, or have a large multi-player component, this can be a large deterrent to piracy (both large scale "bootlegs" and small-scale "sharing").
We also feel it is important to point out that there are many "production" problems that can occur with CD Keys of any sort, and can potentially impact both the effectiveness of the protection and the number of support issues that come up.
Some common problem with CD Keys include:
- Labeling errors during duplication / packaging leading to incorrect or missing CD Keys
- Users mistyping the CD Key
- Users "losing" their CD Key (especially if they need to reinstall it on a new machine)
- Users "sharing" their CD Key without being aware of the consequences (i.e. they won't be able to play online any more)
Less common problems include:
- An internal "leak" of the valid CD Key list which ends up on the Internet
- Users buying the software, getting the CD Key, and then returning it
Once these problems are overcome or accepted, server-based CD Key validation offers some unique features not present in any other anti-piracy scheme. These features include:
- The option to delay enforcement of the protection until the game has generated "critical mass"
- The ability to actually track usage of pirated vs. legal copies of the game
- Hourly and daily numbers for tracking play of the game online
- Unique potential for data mining
All of the data that is tracked is done completely anonymously so that the privacy of your users is protected.
There are actually three layers of protection provided by server-based CD Key validation, each layer targeted at stopping a particular type of piracy:
- You must have a valid CD Key to play online
- No two people can play online at the same time with the same CD Key
- Any valid CD Key can be disabled if it is distributed / abused
This CD Key SDK consists of two very simple portable C APIs - one for the client that encodes the CD Key for sending to the server and another for the server that sends the CD Key to the validation server and authenticates the clients. We believe all of the code to be disclosure safe - in other words, even if the entire source for the system were published, it would be impossible to circumvent it. This is one of the reasons we feel confident in distributing full-source to developers - we welcome your attempts to "break" the system, even from within. We still obfuscate some of the communications to help guard against the "annoyance" factor of thousands of hackers trying to break into our key server through a plain-text interface, but even without this, the system would be totally secure.
Additions to your current code will be fairly minimal, and there is plenty of flexibility for you to implement the SDK in a way best suited to your game.
Fully working examples of both the server and client code are included for testing / reference. This document provides a step by step set of instructions for implementing the CD Key SDK.
How It Works
Terms
The following terms are used throughout this document.
- Server
- The machine that is "hosting" the game and to which the clients connect
- Host
- Same as a server
- Client
- A single player / machine that connects to a server / host
- User
- Same as a client
- Validation Server
- The server run by GameSpy which validates CD Keys and tracks online users
Process
- A list of valid CD Keys is generated by the developer and put on the CD cases during packing. The keys must be self-validating, i.e. there is a function that can determine whether the key is mathematically valid. An example of a CD Key generation/validation pair is included in the SDK. The actual CD Keys used should be less than a 0.0001% subset of the possible keys (to assure that "guessing" a valid key is nearly impossible)
- On install/run of the client, the user inputs the CD Key. The client validates that the CD Key is (mathematically) correct to check typos / made up keys and allows the user to play the game.
-
On connection to a server, a handshake occurs to exchange the key
- The server sends a "challenge" string of random data to the client - note that this challenge string can contain a maximum of 32 characters.
- The client computes a set of hashes based on the challenge, its CD key, and a random value and passes them back to the server
- The server sends the challenge and hashes to the validation server
- The validation server checks its CD Key database to determine whether the hashes are valid. If they are not, it returns an error to the server.
- The validation server then checks to see if another user with that CD Key is online. If one is, then it first queries the old server, to make sure that user is still connected (in case the server crashed), and if they are, it returns an error to the new server.
- When the client logs off or the server shuts down a message is sent to the validation server to take the CD key offline.
Miscellaneous
All game server to validation server messaging is done via UDP, and in case of a dropped packet or missing data, a "positive" result is always assumed (so no user with a valid key will EVER be locked out). Because the protocol uses UDP, there is always a chance that the validation or reply packet might get dropped, allowing a user with an invalid CD Key to play, but the chances of this occurring is quite small (probably 1-2% or less for most servers).
It is technically possible for a cracker to modify the server code to prevent it from checking CD Keys (i.e. allow any user to connect / play on that server). This does not tend to be an issue in most cases, since the vast majority of server operators / game hosts will want to prevent pirates from playing on their servers. However, we have specifically designed the code to be difficult to find and disable on the server. For additional protection, you can choose to allow the CDKey SDK integrate with the Query and Reporting 2 SDK. If a cracker attempts to prevent the server from validating CDKeys, they will end up preventing the server from being listed on the public server list. Of course the most important fact is that there is nothing that can be done on the game client-side to remove or weaken the CDKey protection.
Internet-based validation obviously does not apply to games played on a local LAN (not connected to the net), and in general, the code does not need any changes to reflect this (since no reply will be returned from the validation server, all clients will be considered valid). However, the current server API does do a local check of CD Keys, so that no two players with the same key can connect to the same server (even on a local LAN). You may wish to change this functionality to allow 2 or more players to "share" a CD Key on a local LAN (e.g. for "clone" installs).
Testing
When you are ready to begin testing your implementation of the SDK, you can start by using game ID "0" and the test keys listed below.
Once you've generated your own list of unique keys for your game, you can use the web administration interface described below to add them. The list of keys can be changed or added to later if needed.
Test Keys
2dd4-893a-ce85-6411 4bdb-27e9-ecf8-c042 6585-2eeb-c544-9dd2 42ea-082e-74e5-15b6 7bca-b5e2-47e4-42d1 47a0-84e7-bf51-16f4 899e-040f-fc85-72eb 1156-ba66-a3f2-47b3 22f2-dce2-ce67-c8aa 9131-3dd3-ceb6-c292 5022-bcea-5312-4348 468b-bb7e-f5f8-3936
Web Administration Interface
The CDKey SDK is supported by a full-featured web interface for administering individual keys, batches of keys, and obtaining usage and abuse reports. Multiple users from the publisher and developer can be set up with accounts for secure access to the site.
Account Setup
Each user that requires access to the system will need to have an account set up with specific permissions. To set up an account, contact devsupport@gamespy.com.
You will need to specify the e-mail address of the user who needs access, and the set of permissions they will be granted.
The following individual permissions are available:
- View key reports
- Allows the user to view any of the pages in the reports section (detailed below)
- Add new keys
- Allows the user to add individual keys or batches of keys for the game. Note that you will be billed for any keys added in accordance with your licensing agreement.
- Enable / Disable keys
- Allows the user to enable or disable single keys or batches of keys
- View key list
- Allows the user to download a plain-text listing of all keys for in a batch. This should only be used for testing and key list verification.
Requests to disable accounts should also be sent to devsupport@gamespy.com.
Authentication is done via the GameSpyID system. All users should sign up for a GameSpyID at www.gamespyid.com prior to contacting the developer relations staff for account setup.
Once the account has been set up, the developer relations team will contact the user with the appropriate URL for accessing the admin system.
Main Menu
After logging in to the CDKey Admin site, a menu of options will be available, based on the permissions granted to the active account. Each option is described in detail below.
View Key List
Selecting this option will allow you to select a batch of keys and download them in a plaintext file, one key per line. This can be used to verify the list of keys for a batch against other sources. Users must have the "View key list" permission to access this page.
Enable / Disable Keys
This page allows an admin to enable or disable single keys or batches of keys. On the top portion of the page is a list of key batches. Uncheck a batch to disable the entire batch, or check it to enable. This can be used to disable beta keys or press keys after they should no longer be used (assuming those keys have been added as a separate batch).
The page also includes a text entry box where you can paste a list of individual keys, one per line, to be disabled or enabled. Typically this is used to disable keys from returned copies of games or when a known set of keys needs to be disabled. The enable/disable keys permission is required to use this page.
Add New Keys
Keys are added to the CDKey system in batches. Each batch has 1 or more keys in it (typically thousands) and can have a name and comment associated with it. For example, if you generate a separate list of keys for each region your game will ship in, you can upload them and name them individually. This allows you better control if the keys for one region or pressing of your game are destroyed, and allows you to view some reports broken up by the batch a key was in.
On the Add New Keys page you should specify a batch name and comment, then select the keys to add. You can either upload an ASCII list of keys from your hard drive (one key per line), or if you are adding only a small number of keys, you can paste them into the provided text box.
Keys can also be generated by providing a set of generation parameters.
A user must have the Add new keys permission to add a new batch of keys.
Reports
The CDKey system includes a number of reports that will help keep you informed about what is happening with your game online, research key usage, and detect abused keys so they can be disabled.
Users must have the View key reports permission to view these reports.
Batch Information
The batch information report provides a summary of information about the individual batches of keys that have been uploaded for you game. Each batch has the following information provided for it:
- Batch name
- The name of the batch, provided when it was uploaded
- Add date
- The date the batch was first added to the system
- Admin account
- GameSpyID number of the admin who added the batch. You can click this link to see the user details.
- Comment
- Comment that was provided when the batch was created (if any)
- Disabled
- Flag that shows whether the batch has been disabled
- Total keys
- Total number of keys for this batch
- Total used keys
- Number of distinct keys from the batch that have been used online at least once
- Total active keys
- Number of distinct keys from the batch that have been used in the last 30 days
A totals line is provide that sums the numbers from all batches.
Overall Usage
The overall usage report gives usage information for all batches of keys between a range of dates. To generate the report, you select the start date, end date, and data interval you are interested in.
Reports can be generated by hour, day, week, or month.
Each interval on the date range specified will contain the following data:
- Total number of authentication attempts on that date (valid or invalid)
- Number of authentications that were denied due to an invalid CDKey
- Number of authentications that failed due to the CDKey already being online
- Number of keys that were authenticated for the first time on that date (i.e. "new users")
- Number of authentication attempts for disabled CDKeys (may include multiple for the same disabled key if multiple attempts were made)
Key Information
The key information report allows you to specific a specific CDKey to get information about it and its usage history. This report is also linked from other reports to give additional information about a specific key. If the user has Enable/Disable key rights, a button is available on this page to disable the key (or re-enable it).
The following information is available about each key:
- Enabled
- Flag that indicates whether they key has been disabled
- Origin Batch
- Name of the CDKey batch that includes this key
- Plain Key
- The plain-text value of the key
- Key Hash Value
- The hashed version of the key (which is what is sent from client to server)
- Total Uses
- The total number of successful authentications with this key
- Total Conflicts
- Total number of times someone attempted to use the key while it was already in use
- Recent Conflicts
- Number of times the key was in conflict during a recent period of time (currently 7 days).
- Recent Use History
- This list has the last 20 dates/times and client IP addresses that used the key. It can help determine whether a key is being shared by multiple users.
- Abuse History
- This list shows the last 100 instances of abuse for the key, including a reason for the abuse (e.g. the key was already online), and the client/server IPs that were involved in the conflict.
Disabled Keys
The disabled key report is used to view the list of recently disabled CDKeys. The date and user that disabled the key are available, and a link is provided to the key to view key information and re-enable the key if desired.
Abuse Information
The Abuse Information report allows you to view the top keys in conflict (e.g. someone attempted to use the key multiple times online at the same time) on a specific range of dates. For example, you can set it for the past week to see just the keys that were abused in the past week. The keys are sorted from most abused to least, and a link is provided to the key information page for the key, where the abuse can be investigated and the key can be disabled.
File Manifest
The following files should be included with this package. If any of the files are missing, please contact devsupport@gamespy.com.
- File
- Description
- gcdkeyc.c
- Client API code
- gcdkeyc.h
- Client API Header file
- md5c.c
- MD5 Hash code
- md5.h
- MD5 Hash Header
- gcdkeyclienttest.c
- Sample client application, talks to the sample server application
- gcdkeyclient.dsp
- DevStudio project for the Client API / sample
- gcdkeys.c
- Server API code
- gcdkeys.h
- Server API Header file
- nonport.c
- System-dependant code (sockets, etc)
- nonport.h
- Header for system-dependant code
- gcdskeyservertest.c
- Sample server application, accepts connections from sample client
- gcdkeyserver.dsp
- DevStudio project for Server API / sample
- gcdkeygen.c
- Sample key generation / validation code
- gcdkeygen.dsp
- DevStudio project for key gen sample
- gcdkey.dsw
- DevStudio workspace with client, server, and keygen projects
- gcdkeyserver_qr2.dsp
- DevStudio project for Server API / QR2 Integration sample
- gcdkeyservertest_qr2.c
- Sample server application, plus integration with QR2 SDK
Implementation
Step 0: (Server) Initialize the CD Key API, Think, and Shutdown
Somewhere in your server startup code, call gcd_init with the game ID you have been given to initialize the API sockets and structures. The SDK supports using multiple game IDs simultaneously. You may need to do this if, for example, you need to authenticate multiple CDKeys per-use (e.g. one for the main game, one for a mission pack), or your game server supports multiple products and needs to authenticate each product separately.
In your main game / message loop, call gcd_think to allow the API to process any pending authorization requests / messages. This function should be called at least once every 10-100ms and is guaranteed not to block (although it may make a callback if an authorization response has come in). If your game uses the Query and Reporting 2 SDK, you can place this call in the same area as the call to qr2_think.
In your server shutdown code call gcd_shutdown to release the socket and send disconnect messages to the validation server for any clients still on the server.
Step 1: (Server) Send a challenge string to the client
During the client connection process you need to send the client a random challenge string. This challenge will be used as part of the response hash. You will need to pass this challenge along with the user's response to the gcd_authenticate_user function, so be sure to hold onto it. The challenge string can by any combination of letters / digits. 6-8 characters should be adequate, and the string has a maximum limit of 32 characters.
Step 2: (Client) Respond to the challenge
When the client receives the challenge string it should calculate a response using the gcd_compute_response function in the Client API.
Pass the client's CD key and the challenge string into the function and it will return the response string, a 72 character ASCII string. Send this response back to the server.
Step 3: (Server) Begin the authentication process
Once you have received the client's response, you can call gcd_authenticate_user to send an authentication request.
void gcd_authenticate_user(int gameid, int localid, unsigned int userip, char *challenge, char *response, AuthCallBackFn authfn, RefreshAuthCallBackFn refreshfn, void *instance);
- gameid
- the game ID issued for your game
- localid
- a unique int used to identify each client on the server. No two clients should have the same localid.
- userip
- is the client's IP address, preferably in network byte order
- challenge
- the challenge string that was sent to the client
- response
- the response that the client received
- authfn
- a callback that is called when the user is either authorized or rejected. This function will be called within two seconds of gcd_authenticate_user, even if the validation server hasn't responded yet.
- instance
- any user-defined data you want to pass into the callback function (e.g. an object or structure pointer, or NULL). The example server uses this to pass in the array of client structures.
This function will return immediately, and you will have to wait until the callback is triggered to determine whether the client is valid or not. During this period (usually 100ms or less, but up to 2 sec max) you can hold the client in a limbo-state, or allow them to enter the game (and disconnect them if a negative response comes back).
Remember that you need to be calling gcd_think during this time, or the callback will never be triggered. You should be calling gcd_think even when not waiting for a callback, since it also handles processing on "online" queries from the validation server.
Step 4: (Server) Create the Callback
You will need to create a callback function that is called once the validation server responds with the client's authorization status (or a 2 second timeout occurs).
The prototype for this function is:
void AuthCallBackFn(int gameid, int localid, int authenticated, char *errmsg, void *instance);
- gameid
- the game ID you requested authentication for
- localid
- the id that you passed into gcd_authenticate_user, and indicates which user this callback is referring to (since multiple authentication requests can be sent before the first is returned).
- authenticated
- a 1/0 value that indicates whether the user was authenticated or not.
- If the user was not authenticated, errmsg contains a descriptive string of the reason (either CD Key not valid, or CD Key in use). Errmsg is never NULL, so if there is no message it will be an empty string.
- instance
- the user-defined data that you requested be passed to the callback
If the client was authenticated you should allow them to continue / enter the game. If not, you should send an error message to the client and disconnect / disable them. You do not need to call gcd_disconnect_user (but you can) as they have already been removed from the APIs internal structures.
Step 5: (Server) Create the reauth Callback
The server should have the reauth callback function defined for reauthentications:
The prototype for this function is:
void RefreshAuthCallBackFn(int gameid, int localid, int hint, char *challenge, void *instance);
- gameid
- the the game id used to initialize the SDK with
- localid
- the index of the player
- hint
- a session id for a client used for reauthentication - this is the skey passed into gcd_process_reauth
- challenge
- a challenge string used for reautentication
- instance
- the user-defined data that you requested be passed to the callback
This function will be called when the validation server requires proof that a player is still online using the cd key being checked. The server needs to send the challenge to the player via its own socket. The player must call gcd_compute_response in order to create a new response. The host/server in turn uses this response to call gcd_process_reauth so that it can prove the client's existence. Otherwise the validation server will consider that client offline.
Step 6: (Server) Call Disconnect when a user leaves
When a user disconnects / logs off the server you should call gcd_disconnect_user immediately so that the validation server can be notified that the user is now offline and the CD Key is marked as available again. If you fail to call gcd_disconnect_user, the user may, in some cases, have trouble connecting to another server (since the validation server AND your game server both think the user is still playing).
Don't be concerned about no notification being sent in the case of server crashes / sudden shutdowns - a user will only be denied access if your server is still responding and thinks the user is online. Any time a "conflict" occurs (a user connects with a CD Key that appears to be in use) the original server is contacted to double check that the user is still connected. If the original server doesn't respond, or responds with a negative, the new user is allowed to connect. Please note that this "double check" is handled entirely by the API code, so if you don't notify the API of a user disconnecting, the API will assume the user is still online.
Query and Reporting 2 SDK Integration
As mentioned in the "How it Works" section, you have the option of integrating the CDKey SDK with the Query and Reporting 2 SDK for additional security on the game server. This integration causes the CDKey SDK to use the networking code in the Query and Reporting 2 SDK for all incoming and outgoing data.
This provides two additional benefits to security:
- Any attempt to disable the CDKey validation code inside the server binary will likely result in the disabling of the Query and Reporting code - thus causing the server to not be listed on the master server list.
- When the CDKey network code is integrated with the Query and Reporting code, our backend can send special queries to the game server to verify that it is authenticating CDKeys correctly. If these checks fail, the server can be banned from the master server list automatically.
Both of these features help prevent people from running public, "cracked" servers that allow all clients to play on them without a valid CD Key. It is still possible for someone to run a "private" cracked server by blocking all network traffic to GameSpy's backend. However, that is really no different than if they were running a LAN server with no Internet access - CDKey validation would be disabled in that case anyway. Preventing cracked servers from being listed on the master server will make it nearly impossible for casual players to find any.
Enabling the Query & Reporting 2 integration is simple, and you should generally enable it unless you have a specific reason not to.
To enable the integration:
- Define the pre-compiler directive "QR2CDKEY_INTEGRATION" when compiling the CD Key SDK. You can add this to the gcdkeys.h file, or as a compiler option.
- Call gcd_init_qr2 instead of gcd_init when initializing the CD Key SDK. You will need to initialize the Query and Reporting 2 SDK prior to calling gcd_init_qr2.
Finally, if you are using the Query and Reporting NAT proxy support to share a socket between your game and the Query and Reporting 2 SDK, you will need to pass all CDKey network traffic to the qr2_parse_query function in addtion to the normal QR2 traffic. You can identify CD Key network traffic by the first byte, which is always 0x3B (";").