facebookarchive / conceal

Conceal provides easy Android APIs for performing fast encryption and authentication of data.
http://facebook.github.io/conceal/
Other
2.96k stars 431 forks source link

Hardware Supported Keychain for Lollipop+ #103

Open JaredBanyard opened 8 years ago

JaredBanyard commented 8 years ago

Can we get a KeyChain class that implements the hardware keystore instead of shared preferences?

siyengar commented 8 years ago

We'll look into the keychain from Lollipop. Do you have any docs of where the storage of keys changed to hardware backed keys? The last time i checked the android keystore stored keys protected by the unlock password.

JaredBanyard commented 8 years ago

http://developer.android.com/training/articles/keystore.html

fabiendem commented 8 years ago

👍 for the feature. Looks like we can generate the key for the user and store it safely in the Android KeyStore. https://medium.com/@stelianmorariu/sharedpreferences-and-android-keystore-c4eac3373ac7 Min API is 18+ though

JaredBanyard commented 8 years ago

Yeah most of the Keystore stuff is pretty late API, we could have it fallback to shared preferences. A lot of the keystore stuff, as I understand it, is broken even on APIs that support it. From my experimentation it's very difficult to rely on a particular handset having the proper encoding or keytype support. There is going to have to be a lot of testing and graceful fallback to ensure operation.

fabiendem commented 8 years ago

Android 4.3 is vulnerable https://securityintelligence.com/android-keystore-stack-buffer-overflow-to-keep-things-simple-buffers-are-always-larger-than-needed/

Is it actually safe to use the default SharedPrefsBackedKeyChain to store the KeyChain? If someone roots the device, wouldn't he be able to access the keys and be able to read the encrypted values? Or does Conceal covers a safe storage of the keys? Like in http://developer.android.com/intl/es/training/articles/keystore.html

Cheers!

fabiendem commented 8 years ago

I can see a beginning of answer in this thread: https://news.ycombinator.com/item?id=7140497 and this one: https://www.reddit.com/r/androiddev/comments/1x6owd/use_facebooks_conceal_library_to_store_api_keys/ Answer being no, right? I am more interested in the Api keys encryption scenario and I believe I am not the only one. Conceal has the advantage to greatly simplifying the encryption process, making the difficult choices for us, compared to the pure Android method... Now with the fragmentation we can see in http://developer.android.com/intl/es/training/articles/keystore.html I struggle to find a simple way to store encryption keys.

mandrachek commented 8 years ago

Using the system keystore probably is not a good idea. The fragmentation is one issue, but there's also the design goal of "Extraction Prevention" - key material is not available to the application process. So if you're not using the "standard" android/java API's for encryption, you can't access the key. This means alternative implementations like Conceal or the crypto used by Realm, are pretty much out of luck - http://developer.android.com/training/articles/keystore.html#SecurityFeatures

fabiendem commented 8 years ago

Thanks, so is there any way to use Conceal with a safe way to store the encryption key? I would imagine the Facebook devs who uses Conceal for the Facebook app store the encryption key in a safe place, encryption is worth nothing otherwise. Are there any good suggestions? Android devs jump on Conceal because it makes encryption easier, but if the default setup is not secured, there must be tons of app not properly secured out there which use Conceal. Or am I missing something regarding the encryption key storage?

Vandalko commented 8 years ago

Based on previous discussion, I assume that the purpose of Conceal is to provide easy encryption mechanism, but the burden to store keys is purely on user shoulders ?

The case I want to protect users against: phone is stolen - data should not be retrieved (assuming that phone was already rooted).

Let's imagine, that keys are in SharedPrefsBackedKeyChain: then patched application is installed (which does not require password) and attacker can see all stored data. It seems to me that hardware-backed storage does not protect against this scenario either.

One can say that password-derived encryption key is a good idea, but then you have to cache password hash somewhere in order to avoid necessity of user login on each application launch.

So, the solution I see (for Android) is to have user data encrypted by password-derived key which is cached on the file system and thus vulnerable (actually, it does not really matter if it's password-derived or not) But, the key itself is additionally encrypted with short pin-code which user must enter each time he launches app. Pin-code is never stored and validated by the fact of success keys decryption.

I'm not a security specialist, so want to hear thoughts from you guys :) Maybe, @fabiendem already have some good solution for his app

fabiendem commented 8 years ago

Hi @Vandalko, I am trying to cover the same scenario than you but moved onto other stories for now. I will have to dig back into this later. Though now I think it's a matter of finding the right balance between the security level you want to achieve and the amount of time you want to spend on this. (and the sensitivity of the data...) In the end even the hardware backed encryption gets hacked by researchers at some point. Still, having the PIN code when you open the app is probably the safest solution as nothing is stored.

mandrachek commented 7 years ago

What do you all think about this idea?

Using the AndroidKeyStore, create an RSA key pair (see https://developer.android.com/training/articles/keystore.html#GeneratingANewPrivateKey). This will work on SDK 18+, and gives you a public and private key, stored in the secure hardware (assuming the device has the secure hardware). We can't get the private key bytes back out, and we can't use RSA keys with AES, but we can get the public key as a byte array, as not being able to share that would be... problematic given the whole concept of asymmetric encryption.

As long as the public key isn't shared anywhere, the byte[] of the public key can then be used as input into PBKDF2 (https://android-developers.googleblog.com/2013/02/using-cryptography-to-store-credentials.html) to generate an appropriate AES key as needed. For example, you might sign a device id with the private key and base64 encode the signature as the password, and then use the public key as the salt.

And then you can use Android's built-in require authentication for key use features (https://developer.android.com/training/articles/keystore.html#UserAuthentication).

helios175 commented 7 years ago

Hello, that sounds interesting.

It's true that how Facebook manages log-in (user is not challenged if already logged in) makes difficult to protect data for current logged in user in case of a stolen phone. If you have other app that behaves differently then you could use the user-challenge (pin, password, something) to generate a key which protects the real data key.

There's a project I'm on but wasn't first on my priorities for now. It involves leveraging the Android KeyStore when possible. The idea is similar but as everything else in computing involves another step of indirection.

KeyStore doesn't allow the user to retrieve data from it. But it can generate RSA pairs and you can use it (it doesn't allow symmetric encryption in old versions at least). But you can use that to encrypt the data key in internal storage. Let use names:

DEK = data encryption key, this is what Conceal would use for the data you want KEK = key encryption key, this encrypts the DEK, in this case it'll be the KeyStore key pair

Therefore:

When app needs the key (at least first time, later it can cache it in memory), it can ask the KeyStore to decrypt the EDEK from disk with its KEK.

The issue with this is that supposedly the Android KeyStore might be wiped if user changes the phone screen lock. That means app should need a backup mechanism to restore the DEK. If you're ok with asking user to login again, then the same mechanism of having a EDEK can be applied with a server provided KEK, or with a key derived from the user password (using PBKDF).

But yes, if you are ok with having a backup method of challenging the user in case the KeyStore is wiped out, this scheme would be totally usable.