8

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?

Drise
  • 4,310
  • 5
  • 41
  • 66
Genadinik
  • 18,153
  • 63
  • 185
  • 284

4 Answers4

4

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......";
aromero
  • 25,681
  • 6
  • 57
  • 79
  • base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY (that you got from the Google Play developer console). This is not your developer public key, it's the *app-specific* 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. – Alex Zaitsev Mar 19 '13 at 14:16
  • This was back in the old days where we had a unique developer key, used for licensing and in-app. – aromero Mar 19 '13 at 16:04
  • 2
    Your Base64-encoded RSA public key for Licensing & In App Billing has moved and can now be found in Goggle Play by selecting your Application then clicking the "Services & APIs" tab. – birdman Jun 14 '13 at 02:49
  • Google specifically advises: ~"**Instead of just storing the entire literal string embedded in the program, construct the key at runtime from pieces or use bit manipulation**" – IgorGanapolsky Sep 02 '16 at 14:11
2

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;
}
Community
  • 1
  • 1
Gabriel Glenn
  • 1,174
  • 1
  • 13
  • 30
1

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.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • 3
    You don't need to hide or obfuscate the public key. Google will sign requests using a secret key (which you (developer) don't have and will not be present in your application). The public key is just used to verify that signature. A cracker can't create a fake purchase by using the public key. – aromero Jul 14 '12 at 12:16
  • 1
    A cracker can replace the public key in app memory with their own, and sign purchases with their own private key. That's why Google recommends that you obfuscate. – Seva Alekseyev Jul 14 '12 at 14:23
  • You are right, I thought you were talking about the key itself. – aromero Jul 17 '12 at 12:28
0

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.

John J Smith
  • 11,435
  • 9
  • 53
  • 72