Android billing - in the file Security.java should the base64EncodedPublicKey be the encoded value?

StackOverflow https://stackoverflow.com/questions/11443880

  •  20-06-2021
  •  | 
  •  

Question

Should I paste the actual public key of my app right into the value of this variable?

Or should I encode it and then whatever the encoded string is, I'd make that string into the value of this variable?

Which should it be?

Was it helpful?

Solution

The public key present in your Android Developer Console (which can be found under 'Edit Profile') is already Base64 encoded. Just copy paste the content of the key in your source file. For example, if you have something like this:

enter image description here

Then in your Security.java:

String base64EncodedPublicKey = "MIIBIjANBgkqhkiG9w0BAQ......";

OTHER TIPS

As the Google sample code for In-app billing say, you should obfuscate this public key.

Instead of just storing the entire literal string here embedded in the program, construct the key at runtime from pieces or use bit manipulation (for example, XOR with some other string) to hide the actual key. The key itself is not secret information, but we don't want to make it easy for an attacker to replace the public key with one of their own and then fake messages from the server.

I use very simple Java code to generate the Java Class that will give me back the public key. The basic idea is to use recursion to recreate the key using inner static class. It's just food for thought.

It's a "good-enough" approach for my niche market. See this stackexchange security question for more information on obfuscation.

public static void main(String[] args) throws Exception {
    String className = genClassName();
    PrintWriter writer = new PrintWriter("C:\\" + className + ".java", "iso-8859-1");
    printClass(className, writer, "XXXXXX-YOUR-PUBLIC-KEY-GOES-HERE-XXXXXXX", true);
    writer.close();
}

private static String genClassName() {
    return "Class" + UUID.randomUUID().toString().replaceAll("-", "");
}

private static String printClass(String thisClass, PrintWriter writer, String key, boolean root) {
    int split = key.length() / 2;
    if (split < 10) {
        writer.println("public " + (root ? "" : "static") + " class " + thisClass + " {");
        writer.println("public static String get() {");
        writer.println("return \"" + key + "\";");
        writer.println("}");
        writer.println("}");
    } else {
        String first = key.substring(0, split);
        String last = key.substring(split, key.length());
        writer.println("public " + (root ? "" : "static") + " class " + thisClass + " {");
        String class1 = printClass(genClassName(), writer, first, false);
        String class2 = printClass(genClassName(), writer, last, false);
        writer.println("public static String get() {");
        writer.println("return " + class1 + ".get() + " + class2 + ".get();");
        writer.println("}");
        writer.println("}");
    }

    return thisClass;
}

You need the public key in the program's source code so that you can check the signature. Yes, there's nonzero, unavoidable risk that a cracker will find it, replace it with a fake, and feed your program fake purchases.

You cannot completely hide the key from prying eyes, but you can obfuscate. You can break up the Base64 string into several string constants in different spots and concatenate them before use. Better give the chunks inconspicuous names (not like MY_PUBLIC_KEY_PART_4). You can also apply an additional layer of soft encryption to it - something like XOR a value. You can add an integrity check - make sure the key has not been spoofed (say, store the hash of a key elsewhere and check). But this is all still security via obscurity - a determined enough hacker will get through.

Also consider ProGuard, the built-in code obfuscation tool.

If you have a server component as part of your app, then you can move most of the elements of your security, including your public key, to your server. On the server, you can generate the nonce and verify the purchase (I've moved mine to a RESTFul WCF service). If your server component is .NET based, then you'll probably have to generate a modulus and an exponent from your public key so that you can use the RNGCryptoServiceProvider class. There's a Google I/O video which gives an overview to In-App Billing amongst others.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top