10

I'm using the Android Keystore to store an asymmetric cryptographic (to decrypt a file containing an asymmetric key). I did that because I want to encrypt a large set of data and an asymmetric isn't enough ans they keystore has symmetric keys since SDK 23.

  • In classic HSM you can't access to the cryptographic keys, you only send your data and the HSM does the cryptographic operations. But in Android you retrieve from the Keystore the key to do manually the operations (With Cipher etc..). Is it safe?
  • If it's not safe, is it possible to wipe the keys from the memory after using them? (At the end of my functions for example)
  • If it's safe, what are the risks? Having the RAM corrupted by a virus?

4 Answers 4

10

Let's take a look at the Android Developer docs "Android keystore system". We'll need to break this down depending on how you use the KeyStore object. If you're using the Android KeyStore KeyStore.getInstance("AndroidKeyStore"), then:

1) If the device the app is running on has hardware-backed secure storage, then

Key material may be bound to the secure hardware (e.g., Trusted Execution Environment (TEE), Secure Element (SE)) of the Android device. When this feature is enabled for a key, its key material is never exposed outside of secure hardware.

The "Android keystore system" article gives more info on how to use this feature.

2) If the device does not have hardware-backed secure storage, then:

Key material never enters the application process. When an application performs cryptographic operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to be signed or verified are fed to a system process which carries out the cryptographic operations.

Presumably this system process is written in C where they have more control over memory management and can zeroize the key properly when it goes out of scope in your application (which leads me to my rant about garbage collectors...)

3) If for some reason you use KeyStore.getInstance("JKS") as in the examples here - maybe you need access to the private keys for some reason, or you need to load / store the private keys in a .jks file - then No, you can not wipe it: because the Java garbage collector is famous for returning memory to the OS without clearing or zeroizing it. From the Android developer docs, I don't see any evidence that the Dalvik garbage collector works any differently.

Moreover, one of the mechanisms of the Java garbage collector is to make a copy of any heap variable that's currently referenced by your program and then free the old heap. This means that a copy of your private key may be freed back to the operating system even before it goes out of scope.


Bottom line: If the Android KeyStore object is used properly, your private keys will remain securely inside the Trusted Execution Environment (TEE), Secure Element (SE)) or System process.

If for some reason you do bring the private key into your app, then all bets are off because in Java / Dalvik / Android, once something is in your app's memory, it is nearly impossible to clear or zeroize it.

10
  • 1
    "...So this would arise if you explicitly bring the key into your application for some reason.." You cannot do this with the Android keystore, there is simply no way to get a copy of any of the key bytes, unless you've found a weakness in the keystore implementation. Commented May 30, 2018 at 0:22
  • @JamesKPolk Ah, I don't claim to be an Android developer and only had a quick look at the docs. Please post an answer so I can learn something! Commented May 30, 2018 at 0:56
  • 1
    I've been looking into this recently, and using pmdump etc. - the default implementation of SecretKeySpec makes multiple copies of your key bytes that you can't zero out (private members). Even when I wrote my own (it's pretty simple) I could still detect the key in memory after importing into the AndroidKeystore then zero-ing out the memory. Looking at the source it's hard to see why, but there is some sort of RPC boundary (IKeystoreService) that I haven't looked on to the other side of. I assume the RPC server is running in a different process - its memory may hold the keys too. Commented Aug 7, 2018 at 3:15
  • @DylanNicholson Neat. The java garbage collector is famous for leaving copies of stuff in memory. Out of curiosity, does the same happen on an Android device with e TEE or SE where the key was generated in hardware? Commented Aug 9, 2018 at 16:14
  • Using a TEE won't help in the case you're importing your own key into it. Any key generated inside the TEE should be fine, but in that case it's no use for performing symmetric key encryption/signing where there's another party that needs to do the corresponding decryption/verification. I also found an issue in the implementation of the RPC stub that talks to the keystore that leaves copies of the key in memory. If you want to be uber-careful you're better off writing your own stub to make the RPCs. Commented Aug 9, 2018 at 23:02
5

The other answers cover everything pretty well, but one aspect seems to be misunderstood. As the other answers quoted, ...

Key material never enters the application process. When an application performs cryptographic operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to be signed or verified are fed to a system process which carries out the cryptographic operations.

What this means is that an Android application can't retrieve any of the bytes of the key through any supported means. This enforcement is possible because Android (and Java) get access to raw key material through a single method, Key.getEncoded(), in the Key interface. For keys that are managed by the Android keystore, Key.getEncoded() returns null.

3
  • 1
    Neat. Does it still return null if you're sharing your KeyStore in a password-protected .ks file? Commented May 30, 2018 at 11:47
  • 1
    @MikeOunsworth: A file-based keystore would not have the same protections and thus getEncoded() would not return null. Commented May 30, 2018 at 12:37
  • 1
    Neat that Key.getEncoded() returns null for some KeyStore types, thanks! Commented May 30, 2018 at 13:41
0

If you really DO need to import key data into the AndroidKeyStore (e.g. you need to perform some operation with it that the key store doesn't support), it's not immediately obvious how to ensure it doesn't remain in application memory. However I've been toying with this myself and it seems you're pretty safe if you do the following:

  • Ensure your key data is only ever stored in a byte[] or similar (not a String or other object that may copy its data).
  • Implement your own *KeySpec class that doesn't make any copies of the data (the default ones do, and there's no straightforward way to clear the copied data as it's private)
  • Overwrite the byte[] holding the keydata as soon as it's placed in the keystore.
  • The key bit: immediately store ANOTHER dummy entry in the keystore using zero or junk data. This appears to be only way to wipe out the copy that is made while Parcelling the data to send via RPC to the keystore service.

Hope this helps.

-1

in Android you retrieve from the Keystore the key to do manually the operations. Is it safe?

From the Android documentation:

Key material never enters the application process. When an application performs cryptographic operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to be signed or verified are fed to a system process which carries out the cryptographic operations. https://developer.android.com/training/articles/keystore.html

So while you manually are using the Cipher class and retrieving your key, this is actually done in a system process, NOT your application. You are correct in that you can echo out the key if you want (which will be unsafe), but simply scanning your application (or the memory used by it) will not yield a key.

If it's not safe, is it possible to wipe the keys from the memory after using them?

No need. The system process that does the operations does this for you.

If it's safe, what are the risks? Having the RAM corrupted by a virus?

The real unsafe scenario is that if the device does not have a secure element, the KeyStore could be read.

From the Android documentation:

If the Android OS is compromised or an attacker can read the device's internal storage, the attacker may be able to use any app's Android Keystore keys on the Android device, but not extract them from the device. https://developer.android.com/training/articles/keystore.html

2
  • 2
    "The system process that does the operations does this for you." Can you back up this statement? Java's garbage collector is famous for returning memory to the OS without zeroizing it, is Dalvik any different? Commented May 29, 2018 at 17:44
  • If you're using the AndroidKeystore to generate the keys for you it's nigh on impossible to verify this as there's no way of knowing what key bytes you should be scanning for in a memory dump. But when you import the key bytes in yourself (which is necessary, for instance, if you want to do ECDH), they're definitely still present in memory after adding to the key store. Commented Aug 7, 2018 at 3:18

You must log in to answer this question.

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