Android Licensing System (Step 4 of 5)

Modify your application to decode and test the license

Don't worry, we have example code, the steps you need to follow are below.

4(a). Download the Application key

On the page for the master key pair you will see the line "Application Key" and two links, "Binary", and "Java". For ease of integration you should click on the "Java" link which will start a download of your application file as a Java class (if you click the Binary link you will get a file which contains only your key.

4(b). Add the code to decode a license to your app

You can use the following code as a template...

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(ANDAPPSTORE_APP_KEY);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey key = factory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] original = cipher.doFinal(LICENSE);
 
Properties props = new Properties();
props.clear();
 
ByteArrayInputStream bis = new ByteArrayInputStream(original);
try {
  props.load(bis);
} finally {
  bis.close();
}

The only two bits you will need to change are;

  • ANDAPPSTORE_APP_KEY comes from the Application Key file you downloaded in step 4(a), so if your application key file was called LicenseAppKey123.java, you would replace ANDAPPSTORE_APP_KEY with LicenseAppKey123.APP_KEY
  • LICENSE This should be replaced by the variable you will store the license key in.

4(c). Add the code to test the license properties

There are six tests you can perform on the license properties (now held in the props variable, the code snippets for these are below;

4(c)(i). Testing the phone number

String licensePhoneNumber = license.getProperty("p");
if( licensePhoneNumber == null ) {
  throw new RuntimeException("** Phone Number Check Failed - Number not in license **");
}
 
TelephonyManager TelephonyMgr =
    (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
 
String devicePhoneNumber = TelephonyMgr.getLine1Number();
 
if(licensePhoneNumber.equals(devicePhoneNumber) == false) {
  throw new RuntimeException("** Phone Number Check Failed - Number does not match license **");
}

4(c)(ii). Testing the Device ID

String deviceId = Settings.System.getString(getContentResolver(), Settings.System.ANDROID_ID);
if( deviceId == null ) {
  throw new RuntimeException("This application will not run on the Emulator");
}
 
String licenseDeviceId = license.getProperty("d");
if( licenseDeviceId == null ) {
  throw new RuntimeException("** Device ID Check Failed - ID not in license **");
}
if( licenseDeviceId.equals(deviceId) == false) {
  throw new RuntimeException("** Device ID Check Failed - ID does not match license **");
}

4(c)(iii). Testing the Expiry Date

String licenseExpiry = license.getProperty("e");
if( licenseExpiry == null ) {
  throw new RuntimeException("** Expiry Date Check Failed - No expiry in license **");
}
 
SimpleDateFormat xSdf = new SimpleDateFormat("yyyyMMdd");
Date expiry = xSdf.parse(licenseExpiry);
 
Date now = new Date();
if(expiry.before(now)) {
  throw new RuntimeException("** Expiry Check Failed - License expired **");
}

4(c)(iv). Testing the IMSI of the user

String licenseIMSI = license.getProperty("ms");
if( licenseIMSI == null ) {
  throw new RuntimeException("** IMSI Check Failed - No IMSI in license **");
}
 
TelephonyManager TelephonyMgr =
    (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
 
String deviceIMSI = TelephonyMgr.getSubscriberId();
if(licenseIMSI.equals(deviceIMSI) == false) {
  throw new RuntimeException("** IMSI Check Failed -IMSI does not match license **");
}

4(c)(v). Testing the IMEI of the device

String licenseIMEI = license.getProperty("me");
if( licenseIMEI == null ) {
  throw new RuntimeException("** IMEI Check Failed - No IMEI in license **");
}
 
TelephonyManager TelephonyMgr =
    (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
 
String deviceIMEI = TelephonyMgr.getDeviceId();
if(licenseIMEI.equals(deviceIMEI) == false) {
  throw new RuntimeException("** IMEI Check Failed - IMEI does not match license **");
}

4(c)(vi). Testing the feature list

You would normally do this to test the type of license a user has. Features in a license do not lock a license to a device, they allow you to have multiple types of licenses for an application (for example; you may want a license per level in a game, in this case the above fields would identify the user or device the license is locked to and the feature list would contain the level or levelsthe user bought).

boolean enableFeatureA = false;
boolean enableFeatureB = false;
String licenseFeatures = license.getProperty("f");
if( licenseFeatures != null ) {
  enableFeatureA = licenseFeatures.contains("A");
  enableFeatureB = licenseFeatures.contains("B");
}