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
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.
Related
I'm reading about store a secretkey (to encrypt/to decrypt data) and seems there is no way achieve that. One can only increase difficult for an attacker accomplish this.
It's really like that?
What I've got so far:
Store in shared preference ( private mode ) - Rooted phone will be able to retrieve it.
NDK C/C++ native code, create .so file - Hard to decompile, but one could call this .so file and retrieve it.
A webserver to store the key, looks useless, if a have to send credentials, a malicious ware could log key taps.
Am I too paranoic?
Why do not you use Android Keystore?it is designed for this purpose
https://developer.android.com/training/articles/keystore.html
The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device
It has considerable advantages over shared preferences or private files like extraction prevention or key use authorization I do not consider storing private keys on the server
Security Features
Android Keystore system protects key material from unauthorized use. Firstly, Android Keystore mitigates unauthorized use of key material outside of the Android device by preventing extraction of the key material from application processes and from the Android device as a whole. Secondly, Android KeyStore mitigates unauthorized use of key material on the Android device by making apps specify authorized uses of their keys and then enforcing these restrictions outside of the apps' processes.
In some devices with dedicated hardware it is implemented on it. As a programmer you can know is a key is hardware-protected
The concept is similar to iOS KeyChain, but whereas IOS KeyChain can store passwords, generate and import cryptographic keys, Android KeyStore only allows to generate cryptographic secret keys by the application ( no import functions)
The keys also can be protected requiring user to unlock the device and / or presenting the fingerprint
For example, to secure a password, is possible to generate a cipher key protected with fingerprint, and use it to encrypt user's credentials that could be stored in preferences
You are correct. Most security experts will tell you there is no such thing as an absolutely secure system. The proper way to think of it is in terms of the level of resources an attacker must use to break your system.
You then balance your security measures between the value of the data and other considerations like the complexity of your solution and other costs.
To elaborate on your examples, assuming you aren't worried about the legitimate owner/user of the phone being the attacker, you can assess as follows:
Rooting a phone is a risk if an attacker gets physical possession. To assess, how valuable is the data versus the likelihood of a phone getting lost/stolen, the person who then has it caring to get the key and knowing how to root a phone.
Obscuring secret information is generally considered useless. I personally think it depends a little bit on the circumstances. Here, again, an attacker would need to root the phone, etc. The problem with obscuring secret information is it only takes one person to figure out what you've done and make that information available to completely lose the value in doing it.
If you have a key logger, what security do you have anyway?
You should look at the possibility of using a "secure element". See this post on the security Stack Exchange for some good information.
Our app needs to ship with several usernames, passwords, and tokens for accessing other web based services. I have done quite a bit of googling on this but cannot figure out how to ship the app with the credentials stored securely. Any advice on how to achieve this would be appreciated.
at the end of the day what you're packing in an .apk file is a Java bytecode that if you Google "reverse engineer java byte code" you'll tools and tutos on how to extract the information on that file. I can think of a few good practices that will help you make your app more secure depending how far you're willing to work on it:
pro-guard: that one is a giving, use pro-guard!
you can use little tricks to make stuff more complicate, to store all those Strings in an encrypted format and decrypt them on run time.
as a nice add-on for the last point: on your Developer console, you'll find "YOUR LICENCE KEY FOR THIS APPLICATION". You can use that key to cript the information during development time, and during runtime acquire the value from Google Play to use it to decrypt. More info about it HERE
This license key can also be used to verify app authenticity.
You could also built those keys as a native library. Strings stored in C++ compiled code are way more complicated to crack than in bytecode.
all in all, might be a good read for you this link: http://developer.android.com/training/articles/security-tips.html
Since it has to be decrypted for the application to use there is no way to securely do it, unless you have the person download the information after they install, but there will still need to be information to get to the data for the application to use it.
The most secure way, if you don't want to trust the user, is to have them send the request to your server, and then your server uses its own credentials to go to the website of interest and return the data back to the user.
This way the data stays protected in one place.
Otherwise someone can get to the credentials if they try hard enough.
I am looking into making my user data secure for android. I come across keyczar. I found the android-keyczar-demo provided by Kenny Root who gives talk on android security at google-IO. However I have a nagging question. Since the keys are packaged in the app, isn't it the case that malicious user can also use that key to decrypt the sensitive data? From keyczar doc, keyczarTool is a command-line tool to create the keys, so it seems that it is not meant to be packaged in the app? I have noticed that keyczar's key can be password protected. However it comes back to hard coding the password in the source code. What am I missing to understand here?
What you are missing is that you can't semantically keep the key secret from your users if you also want those same users to be able to decrypt. That's why DRM will never work.
The reason keyczar has the keytool is that an important part of security is changing your key over time, and so keyczar provides a way to rotate your keys without breaking functionality.
The PBE keysets are there so that a user can enter a password to decrypt, it is definitely not intended to be hard coded. That way given a keyset for an app, you can protect the data from an adversary while providing decryption to your user, by requiring your user enter a password. (Unfortunately this feature is only present in the C++, Go, and C# versions of keyczar--not currently in the java version).
Also if you don't want every user to have the same key you don't have to include the keyset with your app, you could also generate it installation. But encryption in the mobile space is difficult, it's hard to say without knowing what you are trying to do, if it's possible for you to secure what you want or if keyczar is the right fit.
I'm pretty stuck on this. I have a username and password as strings within my application that are used for Javamail; however I of course don't want to leave these as plain text and run the risk of having my application decompiled and combed through.
A few had suggested that I look into asymmetric encryption (Using BouncyCastle possibly ); however I'm still unaware how that would entirely help.
I don't have much, if any, experience in cryptography so bear with me here: If I'm using a public/private key pair and I want my application to be able to read the string - then the decrypting key would be the "public key" but that doesn't really make sense to me because it completely defeats the purpose of the encryption. If I have the encrypting key as the "public key" then all my application could do is encrypt the string - not decrypt it.
So my questions here are:
1) Is my reasoning flawed on this?
2) How do I solve this dilemma?
If you want to store them in the app, best you could do is obfuscate them. Encryption is one way of doing this, but it will stop only the casual 'hacker'. If you have encrypted strings as resources (or class fields), in order to decrypt them, you will need the key to be in the app. If someone would decompile your app, it would be fairly easy to find the key too. You could make this a bit harder by generating the key dynamically, from different places in your code, but, as mentioned above, the attacker could just find the place where the secrets are used and dump the already decrytped stings. There is really no easy way out of this.
You could build a simple Web service that requires authentication using a Google account (which pretty much every Android user has on their device), and have it send the mails on behalf of the user (if that fits your requirements). That way, you would at least know who is sending the mails and block them if they try to use it for spam, go over quota, etc. Of course, they could get a new Google account fairly easily, but if your service is purposefully targeted you will have bigger problems that that. Another downside is that your app will require permissions to access the accounts on the device, which some users might see as a privacy concern.
Rephrasing your question, you want your application to have access to sensitive information which your user should not be able to access. The short answer: find another project to work on because this one is not going to secure your secret. Your best alternative is to provide a proxy service which is on a machine you are certain is secure; let it hold your secrets and let your application contact the proxy for everything it needs to do.
You expressed a primary concern of decomplication to discover your secret. Lets say encryption was viable here (it's not). If I put on my black hat, I would decompile, find the API call which receives the decrypted data in its parameters, and either add additional code to output this data, or just set a breakpoint here.
I want to hide some data that is entered by user in user's phone encrypted. As far as I know I can encrypt/decrypt data using a key/seed value, but if I hide the key value in code, I know it can be found somehow (e.g. decompiling the Java code).
Do you have any suggestions to make the process harder?
It is impossible to hide the key in the app such that a resourceful hacker won't be able to pull it out. You can try to obfuscate the key and make it difficult to find but it will always be do able.
See this: https://www.excelsior-usa.com/articles/java-obfuscators.html#examples
The best option would be to require your users to specify a PIN or password and to use that as the encryption key. That way if the device is lost or stolen the key is still safe and it also prevents someone from decompiling your app and getting the encryption key for all instances of your application.
One of the new features in Ice Cream Sandwich (Android 4.0) is the keychain API. From the Platform Highlights page (emphasis mine):
Android 4.0 makes it easier for applications to manage authentication
and secure sessions. A new keychain API and underlying encrypted
storage let applications store and retrieve private keys and their
corresponding certificate chains. Any application can use the keychain
API to install and store user certificates and CAs securely.
If you're doing this for username/password data, you should checkout implementing an Authenticator.
Since android does not have any secure storage on it ( at least as of 2.2), you would have to write your own.
The only way to do this really securely is to encrypt with a key derived from a user supplied password (PBKDF2/ RFc2898 being the way to that). Crypto is only as secure as your key and if you store that on the phone in anyway, then someone can find it and use it. This allows you to have the user store the key without actually remembering a large AES key.
There may be libraries that do this for android. I wrote one for windows phone that can be found here if you want some basis for how to do it.
If encryption/decryption all happens on the handset, a determined hacker will be able to crack it. You can make life harder by using obfustication, or (if appropriate for your application), adding user input into the encrypt/decrypt code.
If your application requires network connectivity, it might be worth off-loading some of the code to a server running elsewhere, so that encrypted data lives on the device, but keys are downloaded at run-time. Still not hack-proof, but it reduces risks to confidential data on a stolen device.