So you’ve no doubt heard ad nauseam about the problem of piracy of App Store-sold apps, and you may remember our opinion that it’s just not worth going to a lot of time and effort trying to stop it directly.
However, we’re certainly interested in ways to structure your development to avoid the problem, and in-app purchase you also may have heard is an excellent way to approach that as it has not been cracked in the general case. And now that it’s available to free apps, the trial then in app purchase model looks like an excellent one to adopt; we’ll be trying that out soonish.
The problem is, to the accomplished cracker it won’t take too long to figure out how you handle the enhanced functionality within your code. Longer than running a script over the binary like a raw App Store purchase, yes, but that just means there’s more mad leet skillz brags for them there. So you need something that’s really challenging. And from this dev forums thread, here it is:
My first attempt was to make use of the SKPaymentQueue restoreCompletedTransactions. I had it all working and then discovered that calling this results in the user being prompted for their iTunes account password. The user experience wasn’t nice. And then on top of that the returned restored transactions don’t have the original transaction receipt. I wanted to compare that against the original one I was storing after the original purchase. So much for validating that the user has made a legitimate purchase.
Then I started to think about encrypting the data in the NSUserDefaults but then I’d have to deal with export regulations.
Then I remembered the keychain. The GenericKeychain example app shows how to store a user’s password in the keychain. And the password is encrypted, even the backup from iTunes onto your computer is encrypted. And the keychain survives the app being deleted and reinstalled.
So that’s what I’ve done. When my app processes an in app purchase I store a flag as a password in the keychain.
Unless the hackers and jailbreakers have a way to crack iPhone keychains my app should be safe. I’ve done a few other tricks to obfuscate my code so no naïve searches of the app will result in critical strings representing the keychain identifiers being found.
Yeah, that should slow them down pretty darn good. I wouldn’t bother going too deep with the ‘other tricks’, but since the code for this approach can be found in the GenericKeychain sample app; with a couple addings of kSetAttrAccount where kSecAttrGeneric is used in KeychainItemWrapper -init, you can simply call to store in the keychain
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"some key" accessGroup:nil];
[wrapper setObject:@"private value" forKey:(id)kSecValueData];
[wrapper release];
and to retrieve it
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"some key" accessGroup:nil];
NSString *value = [wrapper objectForKey:(id)kSecValueData];
[wrapper release];
So yeah, that looks like a pretty solid security model to use in general, and very likely worth its little effort to slow down the pirate hordes!