14

I want to know how I can achieve strong encryption of a public key present in my Android application.

It's Android's advice that

To keep your public key safe from malicious users and hackers, do not embed your public key as an entire literal string. Instead, construct the string 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 you do not want to make it easy for a hacker or malicious user to replace the public key with another key.

There are certain solutions given like having substrings and encryption, but I want to know how can I achieve it in an efficient manner.

2
  • 1
    For what? For worthless snake-oil "copy protection" in which scenario the user is your potential opponent? Or for a secure protocol in which you are on the user's side?
    – thejh
    Apr 3, 2013 at 18:20
  • According to Google (developer.android.com/training/in-app-billing/…), the aim is: ~"This approach makes it more difficult for malicious third parties to modify the public license key string in your APK file." I am assuming that is the goal you were after - to secure the key in your APK? Sep 2, 2016 at 13:52

3 Answers 3

14

First, note that what you need is not encryption. This advice is about public keys. Public keys are, as the name indicate, not secret (except sometimes for privacy — but when your application's key is in your application, there's no privacy involved). What you need is to ensure the integrity of the public key, i.e. ensure that a malicious entity cannot replace it by a different key.

The application uses the public key to authenticate a purchase order. The normal sequence of events for a purchase is:

  1. The user contacts a Google server and pays some money to purchase an in-app feature.
  2. The Google server issues a receipt for that purchase. It signs this receipt with a private key that never leaves the server.
  3. Your application running on the mobile device downloads the receipt.
  4. Your application verifies that the receipt is genuine, relying on the public key bundled with the application.
  5. If the purchase is a repeatable one (e.g. allowing to download X minutes of protected content, as opposed to unlocking a feature), the application must ensure that the same receipt cannot be used twice (replay attack). It does so by “consuming” the purchase.

The problem is that the user may modify the code or data of your application to put a public key of his choosing instead of the genuine one. In particular, he may put a public key for which he knows the private key. If he does this, he can generate purchase receipts without going through any server, and your application will accept them as genuine at step 4.

What you need to do to protect against this attack is to detect any attempt at modifying the public key. It doesn't matter if the potential attacker can read the public key, as long as he cannot change it. This means your application should contain code that verifies that the key is genuine. But whatever you do, the attacker could change the verification code (just flip a bit somewhere to change if is_genuine(public)key) to if not(is_genuine(key)))...

So you need to make it impossible for the attacker to find the verification code. Not only that: you must make it impossible for him to jump over the verification code and into the interesting part. You need to obfuscate your whole application. But obfuscation is hard if not impossible.

There are only two ways you can benefit from obfuscation:

  • If no one cares about your app, maybe no one will try to crack it. (Downside: you aren't making any money either.)
  • You put a lot of effort into it, and only hope for it to hold for a small amount of time. Note that significant effort must be put into each release: if a lot of software is released with the same obfuscation techniques, someone will find a way to crack it, and all that software will be exposed.

For a success story of obfuscation, I recommend reading Gavin Dodd's story about the game Spyro: YOTD. The key points are that it took a lot of effort, that the objective was only to delay the crack for a couple of months, and that it relied in part on the psychology of the attackers who only spend limited time attacking each game and stop as soon as they've passed the first hurdle.

In most cases, obfuscation will cost you far more than it can benefit you.

So what can you do? As advised in the article: don't verify the purchase on the device, verify it on a server under your control. This is only useful if the result of the purchase comes from a server. For example, if the purchase is for additional content or features, the receipt should unlock the content in the user's account on the server, and the app would download any content that the server lets it have.

5
  • Do you know any library or sample code for server side verification, that works with v3 API?
    – Dr.jacky
    Feb 7, 2015 at 7:38
  • ~"user may modify the code or data of your application". How would the user modify code in an APK? That requires some tremendous reverse engineering techniques. And they'll have to re-package the APK and zipalign it again... Sep 2, 2016 at 13:57
  • @IgorGanapolsky Unpack+edit+repack is not “tremendous reverse engineering techniques”. Even if you aren't familiar with the apk format, it isn't hard to find out what you need to put in MANIFEST and that you need to run zipalign. Sep 2, 2016 at 14:15
  • @Gilles That doesn't cut it. You will still have SMALI files that you will have to reverse-engineer. Did you actually think you can access Java code by simply unpacking an APK file??? Sep 2, 2016 at 14:25
  • @IgorGanapolsky Who said anything about Java code? This question was about accessing data which may be trivially easy to find if it's in a separate file in the apk, up to moderately hard to find if it's embedded in binary form in the bytecode. This question wasn't about modifying the code, which indeed would require standard (not “tremendous”) reverse engineering skills. Sep 2, 2016 at 14:38
10

Whatever encryption you use, it's still on the client's device, so they can decrypt it. You're running into the same problem as DRM systems have, whereby anything you hand over to the user can be modified.

If the security of your application depends on the secrecy of your public key, then you have a fundamental flaw in your architecture, and need to attack the problem from a different angle.

If you're just trying to prevent users from changing the public key so that they can use custom private servers, then the most you can do is obfuscate it and hope for the best.

1
  • 1
    That doesn't provide a specific solution in the context of an Android app. Specifically for In-App billing public key. Sep 2, 2016 at 14:08
7

@Polynomial has pretty much nailed it as usual, but for some expansion on what he means by obfuscate;

As the android documentation suggests, you want to make the public key a little difficult to pull out from the binary. You essentially have two layers of protection;

  1. Build the key at run-time using some reasonably complex approach. XOR is good, some kind of iteration is good, transposition and substitution are good too.
  2. Obfuscate your key derivation mechanism. By this I mean employ anti-debugging techniques to your code. Few developers go to this extent, but it all helps.
2
  • Could i get a sample of doing all the aforementioned steps ? I would also like to implement check sum like MD5.
    – Adithya
    Apr 4, 2013 at 7:23
  • The relative success of (1) partly depends on how you implement it right? For instance, you may have a super complex way of assembling a key, but if you assemble it into a variable and pass it into IabHelper.java's constructor, then an attacker could just replace that variable's value right? I'm thinking that the building of key at run time has to be done only when it is required..
    – Kevin Lee
    Mar 12, 2016 at 16:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .