Sending Dynamic Keys to Black Berry App World

If you'd like to generate a user-specific license key, and you want BlackBerry App World to sell it to the user for you, then you'll need to dynamically transfer the keys to BlackBerry App World. Fortunately, RIM has defined a simple protocol for this transaction, found in a document called ''Dynamic License Flow,'' which you can download here:

http://na.blackberry.com/eng/developers/appworld/Dynamic_License_Flow.pdf

All you need to do is set up a web server to accept a simple HTTP POST command from BlackBerry App World (containing the user's data) and then return the corresponding license key. If you're not familiar with HTTP and how to use servlets, they're explained in more detail in Chapters 9 and 11.Here's the exact HTTP request that Blackberry App World will send to your license key server:

POST /pathfromdeveloper HTTP/1.1 Content-Type: application/www-url-encoded Content-Length: 120 Host: hostfromdeveloper

PIN=12341234&[email protected]&product=product&version=1.2~CCC &transactionid=123&test=false

Note that you specify the pathfromdeveloper and the hostfromdeveloper (along with the URL of your license key server) when you configure this licensing option.

In the body of the POST, you'll receive two pieces of user-specific data: the user's e-mail address and the PIN that identifies the user's device. In this example, you'll use the PIN number, but note that using the e-mail address may be more convenient for users that upgrade their device frequently. (Your game can find out the user's e-mail address through the ServiceConfiguration class of the net.rim.blackberry.api.mail package.)

The transactionid is the one security measure that you can use to protect against fraudulent access. Since this transaction is a simple HTTP request over the open Internet, anyone who knows the URL of your license server can send you a fake request and get a real license key for your game. But you can monitor the transaction ID numbers and reject requests that have unexpected values. Of course, someone who knows your license server's URL and knows how to send a POST request with the right parameters may also know how to read a few packets of data headed for your server, read the transaction ID off of a real request, and use that information to create a transaction ID that will fool your server. Your only line of defense against that attack is that most people won't go through that much trouble to unlock your game, especially if it's not very expensive. This defense is a key part of the security behind other billing methods as well, as shown in the ''Cracking Your Game's Billing System'' sidebar.

When your license server receives the POST from BlackBerry App World, it must return the key in a response with the following format:

HTTP/1.1 200 OK

Content-Type: application/www-url-encoded

Content-Length: 20

key=ABCDEFGHIJK

Listing 5-2 shows a simple servlet that receives the license request from BlackBerry App World and returns a license key based on the PIN. This example servlet was developed for an Apache Tomcat 4.1 server and illustrates the bare bones of what you need to do to implement the BlackBerry App World license protocol. In practice, your license server should include a few additional features such as checking the transaction ID (as explained previously) and recording the transaction data in a database.

Listing 5-2. GetLicense.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import javax.crypto.*; import javax.crypto.spec.*;

* A minimal servlet that returns the license key for

public class GetLicense extends HttpServlet {

* Get the license corresponding to the PIN.

String getLicense(int pin) { String retString = ""; try {

ByteArrayOutputStream baos = new ByteArrayOutputStream();

DataOutputStream dos = new DataOutputStream(baos);

dos.writeInt(pin);

byte[] pinData = baos.toByteArray();

SecretKeyFactory scf = SecretKeyFactory.getInstance("DES"); // The DES key used to generate the license is hard-coded: byte[] keyData = {

(byte)-29, (byte)14, (byte)-22, (byte)35, (byte)-53, (byte)4, (byte)-3, (byte)-48

DESKeySpec keySpec = new DESKeySpec(keyData); SecretKey desKey = scf.generateSecret(keySpec); Cipher desCipher;

// Create the cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); // Initialize the cipher for encryption

desCipher.init(Cipher.ENCRYPT_MODE, desKey); // Encrypt the pin byte[] ciphertext = desCipher.doFinal(pinData);

// Turn the encrypted byte array into a human-readable string DataInputStream stream

= new DataInputStream(new ByteArrayInputStream(ciphertext)); int val1 = stream.readInt(); int val2 = stream.readInt(); stream.close();

} catch (Exception e) { e.printStackTrace();

return retString;

* Use an input stream to convert an array of bytes to an int.

public static int parseInt(byte[] data) throws IOException { DataInputStream stream

= new DataInputStream(new ByteArrayInputStream(data)); int retVal = stream.readInt(); stream.close(); return(retVal);

* Handle the POST request (others are ignored).

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

int length = request.getContentLength(); byte[] content = new byte[length];

// get the input stream to read the user data from BlackBerry App World: InputStream is = request.getInputStream(); int read = is.read(content);

// Many errors are ignored in this minimal example. if(read != length) {

response.sendError(400); } else { // get the PIN from the data: String contentString = new String(content); int startIndex = contentString.indexOf("PIN="); int endIndex = contentString.indexOf("&", startIndex); String pinString = contentString.substring(startIndex+4, endIndex); // it is sent as a hexidecimal string, hence the "16" // argument when parsing it: int pin = Integer.parseInt(pinString, 16);

// Prepare the response data:

String responseString = "key=" + getLicense(pin); byte[] responseBytes = responseString.getBytes(); response.setContentType("application/www-url-encoded"); response.setContentLength(responseBytes.length); OutputStream os = response.getOutputStream(); // send the message os.write(responseBytes); os.close();

response.flushBuffer();

As you can see, this servlet uses the DES encryption algorithm to encrypt the PIN number, and then returns the encrypted PIN. More precisely, it extracts the PIN string from the request, interprets the string as an int, converts the int to a byte array, encrypts the byte array using the DES encryption algorithm, converts the encrypted byte array into two ints, encodes the pair of ints as a String, and then returns the result in a response that conforms to BlackBerry App World's specified protocol. Now all you need is a game that will accept this string as the license key to unlock it, as you'll see in the next section.

CRACKING YOUR GAME'S BILLING SYSTEM

Choosing a billing model for your game means finding the right balance between simplicity and security. Making your game completely uncrackable requires—in most cases—far more effort than it's worth, especially if the game is inexpensive. If the game isn't too easy to crack, but it's easy to buy (such as through BlackBerry App World) and it's sold at a reasonable price, then the cost/effort to crack it will be greater to than the cost/effort to buy it. If you know how to crack your own game, then you can easily decide what level of security is appropriate.

The most basic type of security on BlackBerry App World is via restricted download. In order to download the game directly from BlackBerry App World onto the device, you have to pay. This model, however, is easy for anyone with a basic knowledge of BlackBerry to go around. Once an application has been downloaded, you can use the Desktop Manager to save it onto your PC. This gives you a COD file that you can distribute and upload onto other devices.

Protecting your game with a license key adds an extra layer of protection, but it's not perfect. If you use a single key, naturally the key itself can get posted on the Internet, leaving your game wide open to anyone who googles it. The key pool method is quite secure if there's no simple way of guessing the valid key values, and if there's no simple way of intercepting (and spoofing) the game's call to your server to validate the key. (Of course, if the game doesn't need to contact your server to validate the key, then the pool method is no different than the single method.) Since the extra effort to have the game contact your server is costly (and potentially annoying to the user), the pool method is most useful for games that ordinarily contact your server anyway in order to play (such as networked games).

Using a dynamic license key gives you the advantage that the game can validate itself without contacting your server. The disadvantage is that it may be possible to crack the algorithm used to generate the key. The Access Control example in this chapter uses a symmetric-key algorithm to encrypt the PIN. Since symmetric-key algorithms use the same encryption key for both encryption and decryption, the encryption data (to generate the license key) is present in the game code (since the game needs it in order to validate the license key). BlackBerry's COD file format is proprietary, but it's not too hard to convert it to a JAR file, and from there decompile it sufficiently to find the encryption key. Note that the Access Control example uses the DES algorithm (which is inherently weak enough to be cracked by computational brute force), but even if you replace it with the less-crackable triple DES, you still have the problem that the encryption key is present in the game file. Only a very advanced user can crack your license code in this way, but one person can crack it once and then set up a web site with a simple applet that returns a valid license key to your game for anyone who types in a PIN.

The next obvious idea is to encrypt some identifying data (such as the PIN, phone number, or e-mail address) using asymmetric-key encryption. You encrypt the data with your private key and then place the public key in the game code to decrypt it. Since the BlackBerry has all sorts of encryption and decryption algorithms built in, you could, for example, sign the user's PIN with a digital signature and then have the game validate the signature using your public key (hard-coded/compiled into the game). The main disadvantage is that the signature returned by the built-in signing API is so long that it's not reasonable to expect the user to type it in. Using digital signatures, however, is feasible if you're selling your license from your own site (where the game itself communicates with your site using your own invented protocol) instead of selling license keys through BlackBerry App World.

Then there's the question of how to securely store your key. You can't insist that the user type in the license key every time, so you have to store the information that the game has been purchased. If you merely store a "purchased" flag somewhere in memory, the user may be able to spoof it by creating a fake file that matches the one the game would normally create. You can gain some additional protection by storing the "purchased" flag in the smart card, or by storing the license key itself (instead of a generic flag), as shown in the Access Control example.

If you're not selling through BlackBerry App World, then you have a bit more leeway to create a very secure handshake between your game and your server, or—if you have an agreement with an operator (carrier)—to sell access to parts of your game using SMS short codes (with security ensured by the operator). It's just a question of optimizing your security solution to fit your particular business model.

Was this article helpful?

+1 0

Post a comment