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:
- The user contacts a Google server and pays some money to purchase an in-app feature.
- The Google server issues a receipt for that purchase. It signs this receipt with a private key that never leaves the server.
- Your application running on the mobile device downloads the receipt.
- Your application verifies that the receipt is genuine, relying on the public key bundled with the application.
- 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
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.