4

I have an Android APK which loads in locally stored content files protected by AES encryption, and I want to keep the encryption key secret from all users. Only the app itself should be able to read the key.

My question is this: what's the current best practice for preventing all users from gaining access to the encryption key?

Options I have come across so far:

1) The encryption key is stored in the app's internal storage

2) The encryption key is hard coded into the app in a highly obfuscated form

3) The encryption key is requested by the app from a remote server which returns the encryption key over SSL. The request is authenticated by the server using an API key which itself is hard-coded into the APK (also highly obfuscated).

I'm aware that Android OS prevents apps from accessing the data of other apps (when not stored on SD card at least), so the key could possibly be stored in the app's internal storage, but I can't rely on this because users with rooted phones can simply read everything. So option 1 is out.

Neither of the remaining options offer security, just obscurity, and I'm aware that hard-coding any secret keys inside the APK is a bit of a no-no.

Option 2 at least has the benefit of being far simpler to implement.

Option 3 offers the benefit of the encryption key itself only temporarily residing in memory and is never stored permanently on the device. However an attacker would no doubt be looking at the app's response handler for any sign of the encryption key. There's that, and the API key is hard coded into the app so is discoverable by an attacker.

Are there any better options?

Edit: Regarding the use of password derived keys: the content is encrypted off-app (i.e. the app never needs to encrypt, just decrypt) using a predetermined key, so using a password derived key generated by user password/PIN is not going to work as the resulting key would not match the encryption key. Also, the UX would be adversely affected by this extra password step – we want to load and decrypt the content silently in the background if necessary.

  • 2
    Option #4: Get rid of the APK and build a Web app, so nothing is stored locally. – CommonsWare Sep 15 '16 at 13:35
  • @CommonsWare But then your user has to be online... a) at the start of a session, loading lots of data, or b) over the whole session, loading many small chunks. +Serving the content repeatedly could get very expensive at scale. – chichilatte Sep 16 '16 at 10:34
  • 3
    May I ask what kind of content you're trying to protect? Also, Google already have done a lot of work to make Android DRM-friendly and there're many ways to detect root. Based on the assumption that DRM is never really secure and only serve as a deterrent, obscurity is not the worst idea here. – billc.cn Sep 16 '16 at 14:53
  • Ahh, I definitely need to dig further into the Android DRM framework, thanks. The content I want to protect is a mixture of image, audio and json files. – Darriuk Sep 17 '16 at 10:09
2

You want to protect them in environment, which has more trust than your app's storage (which can get eventually exposed in one way or another).

Frequently, OS vendors implement secure key storage for such purposes. Not knowing a lot about Android, I've heard Android Keystore System (https://developer.android.com/training/articles/keystore.html) is such storage you can use to protect the keys and it is not directly accessible from userland, as much as I can judge from the docs, so it follows your demands.

  • I've looked into Android keystore but the problem is that the app needs to retrieve the key before storing it in the keystore. How does it do this ? It uses option #3, which is insecure. The server sending the encryption key needs a way to authenticate the request from the app, which we do using a secret API key known only to the sever and the app. The API key is hard coded into the app. – Darriuk Sep 16 '16 at 9:08
  • 2
    well, cryptography isn't magic and you still need to derive source of trust from somewhere. if user can have access to anything you store on the phone and you don't trust user, you might want to: (1) either remove decryption process from the phone at all and do it on server on demand from client (2) or store the key on server, but use tamper-resistant authentication regime, where you derive authentication secret from code state. – Eugene Sep 19 '16 at 21:23
1

As CommonsWare stated the ideal scenario would have it so that the key is not stored on the same device as the hardware. But if your application is local to the phone than I can understand why you want to avoid this.

One way to protect the data is to have the key derived from a user entered password/PIN, and therefore is not stored at all. If the wrong user password is entered the data simply won't decrypt. You can obfuscate it further by storing it in a blob. Depending on the type of application this may be ok, but for some apps it would seriously mess with the user experience if they need to enter a password/PIN every time.

  • Are you saying... * the user would provide their secret * the server would encrypt the content using that secret and send the encrypted content to the user * the user can then view the content whenever they supply their secret ? – chichilatte Sep 16 '16 at 9:12
  • I agree I could use a password derived key that gets sent securely to the server, which then encrypts the content and returns the encrypted content file to the app. Some problems with that: 1) I would prefer to pre-encrypt the content, 2) in terms of UX I'd really rather avoid the password step, and 3) that's a big processing overhead for the server. I've edited the original question with this in mind. – Darriuk Sep 16 '16 at 9:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.