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.

4
  • 2
    Option #4: Get rid of the APK and build a Web app, so nothing is stored locally. Sep 15, 2016 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. Sep 16, 2016 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, 2016 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, 2016 at 10:09

2 Answers 2

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.

3
  • 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, 2016 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, 2016 at 21:23
  • You could generate a key pair on the device (and maybe verify it with the key attestation API), then have the server encrypt the content key with the device-generated public key.
    – JBYoshi
    Oct 27 at 2:38
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.

2
  • 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 ? Sep 16, 2016 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, 2016 at 9:16

You must log in to answer this question.

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