9
votes

I'm using AWS Cognito and I need to store some credentials and secrets somewhere inside my android app to use them later to sign in/sign up/log out the users.

Some sources suggested to store the credentials inside project gradle.properties file. From there the credentials will be retrieved as BuildConfig.FIELD_NAME. Can I be 100% sure that those cannot be extracted from the apk when reverse-engineering it?

Another way i was thinking about was to encrypt the credentials using an asymmetric encryption algorithm (with public-private key) and decrypt them at runtime when needed, but again, I need to store somewhere inside my app the public key in order to decrypt the credentials. This doesn't work again, since the public key can be extracted decompiling the apk.

I've done a lot of researching about this but I found nothing to help me in this case. Almost every article was referring to how to store credentials like passwords, but that's not the same case since i'm not retrieving my secrets and credentials from a server or anywhere at runtime. Making an API call to get the credentials is again a bad thing.

So, how can I do this as securely as possible? I'm waiting for your solutions! Thanks

edit: Key store doesn't really work since I have to get the secrets from somewhere before adding them to key store

1
@Killer i don't think it's a duplicate, since i need to have the secret stored somewhere right before adding it to the key storeGabi
Yes, I understand your question more clear now. But the question focuses on the same thing. However the accepted answer only answer the aspect when data is retrieved from external server and saved internally. But the question still have suggestion like usage of NDK in order to save the secret dataKiller

1 Answers

6
votes

This really all depends on how secure you need or want your app to be, and how sensitive are those credentials. Since storing and retrieving them from server-side is not an option, your best bet would be to embed them somewhere in the code. APKs can be decompiled really easily, thus your credentials will always be accessible some way or another. The real question is how difficult you want the reversing process to be.

From there the credentials will be retrieved as BuildConfig.FIELD_NAME. Can I be 100% sure that those cannot be extracted from the apk when reverse-engineering it?

I'm 100% sure it can be retrieved :). Java will not encrypt any strings, and they'll be all stored as raw text in the dex files, ready to be grep'd.

From there, your next steps would be to encrypt the keys in the code, using a static key. Some tools will do that for you, like DexGuard, Dasho, Dexprotector -- you could also come up with your own solution.This article explains it well.

Keep in mind that both your own solution, or a solution provided by a third-party tool might prove easy to reverse: see this example for DexGuard. Please also note that when decrypted at runtime, these credentials will be in clear in the device's RAM, thus allowing a debugger to easily read them.

Your next best bet is to go with encrypted strings inside native code: harder to reverse and track down, yet still doable.

Then you can use whitebox cryptography, again with third-party tools like those proposed by Inside Secure. This will essentially blend both an encryption algorithm and a key into obfuscated native code, which might give you hard to reverse & hard to debug encryption/decryption methods. Here you would only include encrypted credentials in your app, and they would be decrypted securely inside the whitebox. The whitebox is generally very secure (but not impossible to crack), but once decrypted, credentials will be in clear in the device's memory. This would protect more thoroughly against simple decompilation.

Then... I don't think you can go much further than that without involving a hardware solution (KeyStore, embedded Secure Element) and a server to back everything up.