Credential storage enhancements in Android 4.3

Our previous post was not related to Android security, but happened to coincide with the Android 4.3 announcement. Now that the post-release dust has settled, time to give it a proper welcome here as well. Being a minor update, there is nothing ground-breaking, but this 'revenge of the beans' brings some welcome enhancements and new APIs. Enough of those are related to security for some to even call 4.3 a 'security release'. Of course, the big star is SELinux, but credential storage, which has been a somewhat recurring topic on this blog, got a significant facelift too, so we'll look into it first. This post will focus mainly on the newly introduced features and interfaces, so you might want to review previous credential storage posts before continuing.

What's new in 4.3

First and foremost, the system credential store, now officially named 'Android Key Store' has a public API for storing and using app-private keys. This was possible before too, but not officially supported and somewhat clunky on pre-ICS devices. Next, while only the primary (owner) user could use the system key store pre-4.3, now it is multi-user compatible and each user gets their own keys. Finally, there is an API and even a system settings field that lets you check whether the credential store is hardware-backed (Nexus 4, Nexus 7) or software only (Galaxy Nexus). While the core functionality hasn't changed much since the previous release, the implementation strategy has evolved quite a bit, so we will look briefly into that too. That's a lot to cover, so lets' get started.

Public API

The API is outlined in the 'Security' section of the 4.3 new API introduction page, and details can be found in the official SDK reference, so we will only review it briefly. Instead of introducing yet another Android-specific API, key store access is exposed via standard JCE APIs, namely KeyGenerator and KeyStore. Both are backed by a new Android JCE provider, AndroidKeyStoreProvider and are accessed by passing "AndroidKeyStore" as the type parameter of the respective factory methods (those APIs were actually available in 4.2 as well, but were not public). For a full sample detailing their usage, refer to the BasicAndroidKeyStore project in the Android SDK. To introduce their usage briefly, first you create a KeyPairGeneratorSpec that describes the keys you want to generate (including a self-signed certificate), initialize a KeyPairGenerator with it and then generate the keys by calling generateKeyPair(). The most important parameter is the alias, which you then pass to KeyStore.getEntry() in order to get a handle to the generated keys later. There is currently no way to specify key size or type and generated keys default to 2048 bit RSA. Here's how all this looks like:

// generate a key pair
Context ctx = getContext();
Calendar notBefore = Calendar.getInstance()
Calendar notAfter = Calendar.getInstance();
notAfter.add(1, Calendar.YEAR);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(ctx)
                .setAlias("key1")
                .setSubject(
                        new X500Principal(String.format("CN=%s, OU=%s", alais,
                                ctx.getPackageName())))
                .setSerialNumber(BigInteger.ONE).setStartDate(notBefore.getTime())
                .setEndDate(notAfter.getTime()).build();

KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
kpGenerator.initialize(spec);
KeyPair kp = kpGenerator.generateKeyPair();

// in another part of the app, access the keys
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("key1", null);
RSAPublicKey pubKey = (RSAPublicKey)keyEntry.getCertificate().getPublicKey();
RSAPrivateKey privKey = (RSAPrivateKey) keyEntry.getPrivateKey();

If the device has a hardware-backed key store implementation, keys will be generated outside of the Android OS and won't be directly accessible even to the system (or root user). If the implementation is software only, keys will be encrypted with a per-user key-encryption master key. We'll discuss key protection in detail later.

Android 4.3 implementation

This hardware-backed design was initially implemented in the original Jelly Bean release (4.1), so what's new here? Credential storage has traditionally (since the Donut days), been implemented as a native keystore daemon that used a local socket as its IPC interface. The daemon has finally been retired and replaced with a 'real' Binder service, which implements the IKeyStoreService interface. What's interesting here is that the service is implemented in C++, which is somewhat rare in Android. See the interface definition for details, but compared to the original keymaster-based implementation, IKeyStoreService gets 4 new operations: getmtime(), duplicate(), is_hardware_backed() and clear_uid(). As expected, getmtime() returns the key modification time and duplicate() copies a key blob (used internally for key migration). is_hardware_backed will query the underlying keymaster implementation and return true when it is hardware-backed. The last new operation, clear_uid(), is a bit more interesting. As we mentioned, the key store now supports multi-user devices and each user gets their own set of keys, stored in /data/misc/keystore/user_N, where N is the Android user ID. Keys names (aliases) are mapped to filenames as before, and the owner app UID now reflects the Android user ID as well. When an app that owns key store-managed keys is uninstalled for a user, only keys created by that user are deleted. If an app is completely removed from the system, its keys are deleted for all users. Since key access is tied to the app UID, this prevents a different app that happens to get the same UID from accessing an uninstalled app's keys. Key store reset, which deletes both key files and the master key, also affects only the current user. Here's how key files for the primary user might look like:

1000_CACERT_ca
1000_CACERT_cacert
10248_USRCERT_myKey
10248_USRPKEY_myKey
10293_USRCERT_rsa_key0
10293_USRPKEY_rsa_key0

The actual files are owned by the keystore service (which runs as the keystore Linux user) and it checks the calling UID to decide whether to grant or deny access to a key file, just as before. If the keys are protected by hardware, key files may contain only a reference to the actual key and deleting them may not destroy the underlying keys. Therefore, the del_key() operation is optional and may not be implemented.

The hardware in 'hardware-backed'

To give some perspective to the whole 'hardware-backed' idea, let's briefly discuss how it is implemented on the Nexus 4. As you may now, the Nexus 4 is based on Qualcomm's Snapdragon S4 Pro APQ8064 SoC. Like most recent ARM SoC's it is TrustZone-enabled and Qualcomm implement their Secure Execution Environment (QSEE) on top of it. Details are, as usual, quite scarce, but trusted application are separated from the main OS and the only way to interact with them is through the controlled interface the /dev/qseecom device provides. Android applications that wish to interact with the QSEE load the proprietary libQSEEComAPI.so library and use the functions it provides to send 'commands' to the QSEE. As with most other SEEs, the QSEECom communication API is quite low-level and basically only allows for exchanging binary blobs (typically commands and replies), whose contents entirely depends on the secure app you are communicating with. In the case of the Nexus 4 keymaster, the used commands are: GENERATE_KEYPAIR, IMPORT_KEYPAIR, SIGN_DATA and VERIFY_DATA. The keymaster implementation merely creates command structures, sends them via the QSEECom API and parses the replies. It does not contain any cryptographic code itself.

An interesting detail is that, the QSEE keystore trusted app (which may not be a dedicated app, but part of more general purpose trusted application) doesn't return simple references to protected keys, but instead uses proprietary encrypted key blobs (not unlike nCipher Thales HSMs). In this model, the only thing that is actually protected by hardware is some form of 'master' key-encryption key (KEK), and user-generated keys are only indirectly protected by being encrypted with the KEK. This allows for practically unlimited number of protected keys, but has the disadvantage that if the KEK is compromised, all externally stored key blobs are compromised as well (of course, the actual implementation might generate a dedicated KEK for each key blob created or the key can be fused in hardware; either way no details are available). Qualcomm keymaster key blobs are defined in AOSP code as shown below. This suggest that private exponents are encrypted using AES, most probably in CBC mode, with an added HMAC-SHA256 to check encrypted data integrity. Those might be further encrypted with the Android key store master key when stored on disk.

#define KM_MAGIC_NUM     (0x4B4D4B42)    /* "KMKB" Key Master Key Blob in hex */
#define KM_KEY_SIZE_MAX  (512)           /* 4096 bits */
#define KM_IV_LENGTH     (16)            /* AES128 CBC IV */
#define KM_HMAC_LENGTH   (32)            /* SHA2 will be used for HMAC  */

struct  qcom_km_key_blob {
  uint32_t magic_num;
  uint32_t version_num;
  uint8_t  modulus[KM_KEY_SIZE_MAX];
  uint32_t modulus_size;
  uint8_t  public_exponent[KM_KEY_SIZE_MAX];
  uint32_t public_exponent_size;
  uint8_t  iv[KM_IV_LENGTH];
  uint8_t  encrypted_private_exponent[KM_KEY_SIZE_MAX];
  uint32_t encrypted_private_exponent_size;
  uint8_t  hmac[KM_HMAC_LENGTH];
};

So, in the case of the Nexus 4, the 'hardware' is simply the ARM SoC. Are other implementations possible? Theoretically, a hardware-backed keymaster implementation does not need to be based on TrustZone. Any dedicated device that can generate and store keys securely can be used, the usual suspects being embedded secure elements (SE) and TPMs. However, there are no mainstream Android devices with dedicated TPMs and recent flagship devices have began shipping without embedded SEs, most probably due to carrier pressure (price is hardly a factor, since embedded SEs are usually in the same package as the NFC controller). Of course, all mobile devices have some form of UICC (SIM card), which typically can generate and store keys, so why not use that? Well, Android still doesn't have a standard API to access the UICC, even though 'vendor' firmwares often include one. So while one could theoretically implement a UICC-based keymaster module compatible with the UICC's of your friendly neighbourhood MNO, it is not very likely to happen.

Security level

So how secure are you brand new hardware-backed keys? The answer is, as usual, it depends. If they are stored in a real, dedicated, tamper-resistant hardware module, such as an embedded SE, they are as secure as the SE. And since this technology has been around for over 40 years, and even recent attacks are only effective against SEs using weak encryption algorithms, that means fairly secure. Of course, as we mentioned in the previous section, there are no current keymaster implementations that use actual SEs, but we can only hope.

What about TrustZone? It is being aggressively marketed as a mobile security 'silver bullet' and streaming media companies have embraced it as an 'end-to-end' DRM solution, but does it really deliver? While the ARM TrustZone architecture might be sound at its core, in the end trusted applications are just software that runs at a slightly lower level than Android. As such, they can be readily reverse engineered, and of course vulnerabilities have been found. And since they run within the Secure World they can effectively access everything on the device, including other trusted applications. When exploited, this could lead to very effective and hard to discover rootkits. To sum this up, while TrustZone secure applications might provide effective protection against Android malware running on the device, given physical access, they, as well as the TrustZone kernel, are exploitable themselves. Applied to the Android key store, this means that if there is an exploitable vulnerability in any of the underlying trusted applications the keymaster module depends on, key-encryption keys could be extracted and 'hardware-backed' keys could be compromised.

Advanced usage

As we mentioned in the first section, Android 4.3 offers a well defined public API to the system key store. It should be sufficient for most use cases, but if needed you can connect to the keystore service directly (as always, not really recommended). Because it is not part of the Android SDK, the IKeyStoreService doesn't have wrapper 'Manager' class, so if you want to get a handle to it, you need to get one directly from the ServiceManager. That too is hidden from SDK apps, but, as usual, you can use reflection. From there, it's just a matter of calling the interface methods you need (see sample project on Github). Of course, if the calling UID doesn't have the necessary permission, access will be denied, but most operations are available to all apps.

Class smClass = Class.forName("android.os.ServiceManager");
Method getService = smClass.getMethod("getService", String.class);
IBinder binder = (IBinder) getService.invoke(null, "android.security.keystore");
IKeystoreService keystore = IKeystoreService.Stub.asInterface(binder);

By using the IKeyStoreService directly you can store symmetric keys or other secret data in the system key store by using the put() method, which the current java.security.KeyStore implementation does not allow (it can only store PrivateKey's). Such data is only encrypted by the key store master key, and even the system key store is hardware-backed, data is not protected by hardware in any way.

Accessing hidden services is not the only way to augment the system key store functionality. Since the sign() operation implements a 'raw' signature operation (RSASP1 in RFC 3447), key store-managed (including hardware-backed) keys can be used to implement signature algorithms not natively supported by Android. You don't need to use the IKeyStoreService interface, because this operation is available through the standard JCE Cipher interface:

KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry keyEntry = keyStore.getEntry("key1", null);
RSAPrivteKey privKey = (RSAPrivateKey)  keyEntry.getPrivateKey();

Cipher c = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, i privateKey);
byte[] result = cipher.doFinal(in, o, in.length);

If you use this primitive to implement, for example, Bouncy Castle's AsymmetricBlockCipher interface, you can use any signature algorithm available in the Bouncy Castle lightweight API (we actually use Spongy Castle to stay compatible with Android 2.x without too much hastle). For example, if you want to use a more modern (and provably secure) signature algorithm than Android's default PKCS#1.5 implementation, such as RSA-PSS you can accomplish it with something like this (see sample project for AndroidRsaEngine):

AndroidRsaEngine rsa = new AndroidRsaEngine("key1", true);

Digest digest = new SHA512Digest();
Digest mgf1digest = new SHA512Digest();
PSSSigner signer = new PSSSigner(rsa, digest, mgf1digest, 512 / 8);
RSAKeyParameters params = new RSAKeyParameters(false,
                    pubKey.getModulus(), pubKey.getPublicExponent());

signer.init(true, params);
signer.update(signedData, 0, signedData.length);
byte[] signature = signer.generateSignature();

Likewise, if you need to implement RSA key exchange, you can easily make use of OAEP padding like this:

AndroidRsaEngine rsa = new AndroidRsaEngine("key1", false);

Digest digest = new SHA512Digest();
Digest mgf1digest = new SHA512Digest();
OAEPEncoding oaep = new OAEPEncoding(rsa, digest, mgf1digest, null);

oaep.init(true, null);
byte[] cipherText = oaep.processBlock(plainBytes, 0, plainBytes.length);

The sample application shows how to tie all of those APIs together and features an elegant and fully Holo-compatible user interface:



An added benefit of using hardware-backed keys is that, since they are not generated using Android's default SecureRandom implementation, they should not be affected by the recently announced SecureRandom vulnerability (of course, since the implementation is closed, we can only hope that trusted apps' RNG actually works...). However, Bouncy Castle's PSS and OAEP implementations do use SecureRandom internally, so you might want to seed the PRNG 'manually' before starting your app to make sure it doesn't start with the same PRNG state as other apps. The keystore daemon/service uses /dev/urandom directly as a source of randomness, when generating master keys used for key file encryption, so they should not be affected. RSA keys generated by the softkeymaster OpenSSL-based software implementation might be affected, because OpenSSL uses RAND_bytes() to generate primes, but are probably OK since the keystore daemon/service runs in a dedicated process and the OpenSSL PRNG automatically seeds itself from /dev/urandom on first access (unfortunately there are no official details about the 'insecure SecureRandom' problem, so we can't be certain).

Summary

Android 4.3 offers a standard SDK API for generating and accessing app-private RSA keys, which makes it easier for non-system apps to store their keys securely, without implementing key protection themselves. The new Jelly Bean also offers hardware-backed key storage on supported devices, which guarantees that even system or root apps cannot extract the keys. Protection against physical access attacks depends on the implementation, with most (all?) current implementations being TrustZone-based. Low-level RSA operations with key store managed keys are also possible, which enables apps to use cryptographic algorithms not provided by Android's built-in JCE providers.

Comments

Excellent post, thanks.

One question: you write that when an application which created keys has been uninstalled keys will be removed from keystore. I do not see this happens on my Nexus 7. After i uninstalled the application and installed again, it can find key with the same alias.
Should i do something else?
Nikolay Elenkov said…
I haven't actually tested on the Nexus 7, but key files do get removed automatically, you shouldn't need to do anything special. If you are using my sample application, it generates keys with the same aliases after each restart (starting from 0), so that might have something to do with it.
1423 said…
Nikolay, thanks for this enlightening post! Do you know of any way to encrypt and decrypt data using hardware-stored keys (either symmetric or asymmetric, I don't care)? It seems like only signing and verification are possible, but perhaps I've missed a trick with raw RSA?
Nikolay Elenkov said…
See the 'Advanced usage' section of the post.
1423 said…
Thanks for the reply. If I understand the 'Advanced usage' section right, symmetric keys can be stored in the system key store but they won't be hardware protected. The sign() operation is raw RSASP1, equivalent to RSADP. Although you don't say it explicitly, perhaps the verify() operation is raw RSAVP1, equivalent to RSAEP? In that case we could implement encryption and decryption using hardware-backed RSA keys.
Nikolay Elenkov said…
verify() returns true/false so you can't use it that way. Doing public key operations in hardware is not particularly useful anyway, because you can export the public key.
1423 said…
D'oh, I see your point now. Thanks!
manuel miranda said…
But for signing you need the private key which shouldn't be exported.

I don't know if I am asking the same but: This TrustZone which is standardized by Global Platform (they call it Trusted Execution Environment) is, according to them: "The TEE is a secure area that resides in the main processor of a smart phone (or any mobile device) and ensures that sensitive data is stored, processed and protected in a trusted environment".

My question is, can we use it then to perform "secure" calculations as in SE applets or it can only be used to store the keys?
Nikolay Elenkov said…
TEE != TrustZone. TrustZone is merely one way to implement a Trusted Execution Environment (TEE), specific to ARM processors.

Since a TEE application is a program it can do pretty much anything. The downside is that you have to implement an command/reply RMI communication interface between it and the client app running on Android. The implementation in 4.3 performs calculations (sign and verify), it doesn't just store keys.
Tux said…
Hi Nicolay,

Thank you for all your posts, very useful stuff...

I have a problem, I need to configure a EAP Wireless connection to set this up on users phone. I am able to install certificates and then using reflection, to fill the CA_CERT part of the enterpriseconfig for the connection but I cannot acces the client_cert, although, the certificate exists when I list all the user certificates:

I am not copying the whole code but basically:

....
private String ENTERPRISE_CLIENT_CERT = "keystore://USRCERT_CertTom";
....
private String ENTERPRISE_CA_CERT = "keystore://CACERT_CertTom";

/*EAP CA Certificate*/
if(!noEnterpriseFieldType)
wcefSetValue.invoke(wcefCaCert.get(selectedConfig), this.ENTERPRISE_CA_CERT);

/*EAp Client certificate*/
if(!noEnterpriseFieldType)
wcefSetValue.invoke(wcefClientCert.get(selectedConfig), this.ENTERPRISE_CLIENT_CERT);

The EAP CA cert is working and the client field does not change, although, keystore://USRCERT_CertTom exists. How can I have rights to put this one there then? Any idea?

If not I'd like to open the network settings of one particular network programmatically, so that the user just have to choose the client_cert but not the connection...any idea?

Thank you for your help,

Kind regards,
James said…
Hi Nikolay
First of all, thank you for sharing your knowhow! I have been stopping by regularly and almost always found an answer to my security related Android problems here.

We are in the final testing phase of an app that makes use of the new app-private key feature in API Level 18. It's great that no screen lock password is required anymore to store keys.
However, we ran into the problem that all keys are wiped if a user removes his lock screen password, even if the keys were created before the user even had a screen lock password set.

Do you know how the screen lock password relates to the app-private keys? I thought that there is no relation anymore since it is possible to store app-private keys also if no screen lock password is set...
Have you had similar issues?

Best regards,
James
Nikolay Elenkov said…
Look at the code to be sure, but I think the master key is still derived from the lock screen PIN. Therefore, if you clear the PIN there is no way to derive the master key, and the only possible solution is to delete all keys.
James said…
Thanks for your swift reply. Will do.
Arne Riiber said…
Thanks for a great blog! Tried the code samples on a Nexus 7, observed that is_hardware_backed() returned 0 and KeyChain.isBoundKeyAlgorithm("RSA") returned false. A system update from Android 4.3 build number JWR66N to JSS15R fixed this, so is_hardware_backed() returned 1 and KeyChain.isBoundKeyAlgorithm("RSA") returned true. Best regards, Arne.
Nikolay Elenkov said…
Glad it works for you. I guess the JWR66N build didn't include the hardware-specific module, but only the generic OpenSSL implementation.
zuzzuruzzu said…
Hi Nikolay,
i need to make an Android app that save securely an RSA PrivateKey received from a web service in PKCS#8 format encoded in a base 64 String.
Sorry if i loose some information in your article, i want know if i can store an existing key using the KeyStore or is only possible saving key pairs generated as in your starting example?
Nikolay Elenkov said…
You can import keys too, but you need to convert them to PKCS#12 format first. You can do that with OpenSSL or Bouncy Castle.
Oud Player said…
Hi Nikolay,
Thank you very much for this study.
No doubt that Trustzone is very powerful but I still have some concern.

According to QC, non-secured application App1 (running in HLOS) can talk with secured application App2 (running in TZ).
In that case, App1 can load App2 if it knows its name and start to communicate with it through commands agreed by both sides.
I am not a security expert but let's say that a malicious application succeeded to "sniff" these transaction, all the TZ power suddenly fails.
QC agrees on that and said that developers should take the responsibility for building an authentication process between the 2 applications.
Do you have any idea how can it be done in an android OS?

Regards,

Fabrice.
ni said…
Hi Nikolay,

I inherited an Android project which uses your classes to store sensitive information on a device. Unfortunately on 4.3 I get the error "Assertion Error 5" at org.nick.androidkeystore.android.security.KeyStore.state(KeyStore.java:74) when calling KeyStore.state(). I'm guessing this means the execute()-Method on KeyStore.java fails due to some error.

I have updated your code to the latest version as I saw your git comments regarding 4.3, however this did not solve the issue. Do you have any idea what I should try in order to pinpoint / fix this issue? As a side-note: The application is working fine on pre-4.3 devices.

Thanks and best regards,
Hendrik
Nikolay Elenkov said…
Does the sample application work as is? For 4.3 you need to instantiate the KeyStoreJb43 class, it will connect to the new 4.3 keystore service. An even more portable method would be to use the public APIs and wrap your encryption keys with an RSA key generated in the keystore before storing them on disk
Nikolay Elenkov said…
If there is a rogue app that can sniff low level communication, you are already in trouble. The idea here is that it even if it can sniff and send commands, the actual keys cannot be extracted. How exactly you add authentication depends on the particular secure application and the commands it supports.
ni said…
Thanks for your quick reply!

The sample application works for sub-4.3 - on 4.3 I'm getting: Could not find method android.security.IKeystoreService.generate, referenced from method org.nick.androidkeystore.android.security.KeyStoreJb43.generate

I had previously overlooked your IS_JB43 statement and have now added that to my code. Now I'm getting a different error there: java.lang.RuntimeException: Unable to resume activity {myApp.MainActivity}: java.lang.RuntimeException: Unable to resume activity {myApp.CardFragment}: java.lang.NullPointerException - but I'm guessing this is due to the same origin-error the sample application throws.

Any hints are greatly appreciated!
Nikolay Elenkov said…
What device(s) are you testing this on? the android-keystore application works fine on Nexus 4 with stock 4.3 and Nexus 5 with stock 4.4. Any NPEs and other errors in your code I can't really help with, unless it's open source.
ni said…
Unfortunately I can at the moment only test 4.3/4.4 on the Android Emulator (Nexus S) as our development devices are still stuck on 4.2.2 (Samsung Galaxy S4 Mini / SWC-branded).
Is the issue with the sample application possibly related to restrictions by the emulator?
ni said…
As another side note: The sample project works fine under emulator running Android 4.2. So it shouldn't be that.
Nikolay Elenkov said…
The only difference should be that the emulator's keystore is not hardware backed. Try to debug this a little further. 4.2 implementation is completely different, so there is not much point comparing with 4.2.
kycera said…
Hi Nikolay,

I want to thank you, for writing this blog. Many times I was not able to find this information elsewhere. But I am not sure that i get all information right, so to be sure please correct me if I am wrong.

I need to securely store some BigInt values and over them compute access token. Before android ICS ,credential storage was used only for VPN connection with no application control. In ICS we can add a manage certificates and their keys, with is protected by key derived from lock screen pass/pin, but no official way to store not certificate data. By using keystore daemon directly we can store our own byte data in credential storage, but it is not official way and may not work properly on all devices. In JB4.1 was added hardware-backed credential storage but also with no official API to store custom data, and no API to recognized if hardware-backed credential storage is available. ON JB4.3 API was set public, and we can check if hardware-backed is available. We can generate and using keys outside Android OS, and if it is on hardware-backed even on root we are not able to steal keys from device. But there is still no official way how to store custom data. And there is no way how to use hardware-backed storage to execute custom cryptographic protocol outside Android OS(like applet on SmartCards). So if I am wrong please correct me.

Thanks in advice. Marek
Nikolay Elenkov said…
You can generate RSA keys using the 4.3 APIs and use them to wrap your own symmetric keys. Then use those to encrypt whatever you want.

You cannot change secure (TrustZone) applications that are pre-installed on the device, because that part of device is locked and only the manufacturer/Google has the keys. However, for most cryptographic protocols you only need private key operations (signing,etc) to be executed using the hardware-backed keystore. You can build pretty much anything (SSL, etc.) on top of that.
kycera said…
Thanks for reply, by wrap you mean encrypt with RSA and store on device normal memory?

I need to implement custom "protocol" (it have few keys witch consit BigInteger values, and over them I compute few mathematic operations add, subtract, power mod..). And I try to find way how to idealy do the computing in TrusZone, or at least store keys securelly. But like you said TrustZone is locked foe changing applications.
Oud Player said…
Hi Nikolay,

What occurs in terms of SW architecture when Android is to be used with proprietary TrustZone module?
I believe that the new Android API needs to be connected to TZ API.
I heard that the Global platform group has provided a generic SW layer working on top of ARM TZ API (called tzapi).Have you heard about it?
Has Nexus4 used JB4.3 API to use Keystore with Qualcomm's TZ module?

Regards,

Fabrice.
Nikolay Elenkov said…
The GP standard defines an interface, not an actual implementation. I have some discussion about it in the original post on the topic ('Jelly Bean hardware-backed credential storage'). This post mentions how the keystore (keymaster engine) talks to the TZ app -- by sending commands through /dev/qseecom.

Cf. http://nelenkov.blogspot.com/2012/07/jelly-bean-hardware-backed-credential.html
Oud Player said…
Hi Nikolay,

Sorry but things are still confusing me,
The example you gave when commands are sent through qseecom is only dedicated to QC according to my understanding.
Let's say that I want to develop a new secure storage module and I want it to be Android portable, can I use the GP interface? For example:

JB4.3 Keystore API --> GP API --> GP TEE --> HW
In that case I connect Android API to GP API. Is it even possible or should I get rid of Android API and assume that application will use the GP API?

Regards,

Fabrice.
Nikolay Elenkov said…
If you are developing everything from from scratch, you can do whatever you want. However, typically you will use some commercial secure OS and you have to use the API they provide. Not sure what you mean by 'GP API'.
Oud Player said…
Hi Nikolay,
GP API = Global Platform.

My only concern is where the SW layers are located from architecture perspective.
This is what I understand if we take OMAP4460 example:

1 - HW security module is M-Shield.
2 - TEE running on top of the HW is provided by TRUSTONIC and is compliant to Global Platform API.
3 - All this is fully integrated with Android 4.0's security API.

From this, I understand that Android's APIs are connected to the Global Platform API for any application to be able to access the secured world.
Am I right?

Fabrice.
Brian Deblanc said…
Thanks for all your posts - it makes things much easier.

I am currently working on an application that only supports 4.0.3+. Do you feel the private APIs are pretty safe to use at this point? I figure I can tackle new releases as they come out, I'm more worried about compatibility between ICS+ devices.

I can't think of any other way to store an encryption key on the device other than using this, the other solutions all involve having a user input something (pin or password) that would be used to generate the key on the fly.

I toyed around with the KeyChain as well, but I can't expect my users to understand the dialogs that Android supplies for allow use of the key/certificate.
Brian Deblanc said…
Also, on my Nexus 5 running 4.4.2 I get a NoSuchMethodException when trying to access android.security.IKeystoreService.is_hardware_backed . Any idea if this changes for KitKat?
Nikolay Elenkov said…
It's unlikely that vendors will change the internal API, but you never know. Test on Samsung, HTC, Sony and you should be OK for the most part.

4.4 supports other algorithms besides RSA, so you need to pass the algorithm name. Check the API docs for details.
Brian Deblanc said…
Thanks for the info.

For your reference I was able to test the AES encryption function on 4.0.3,.4.1.1, 4.1.2, 4.2.2 and 4.3 on various Samsung, Htc, and Motorola phones - all worked fine.
Nikolay Elenkov said…
Thanks. I've pushed an update that works on KitKat and adds an EC sample.
Brian Deblanc said…
Thanks much!

It looks like your latest push broke it on 4.3, because now it can't find is_hardware_backed() with a string arg to bind to in 4.3.

One final question - I'm assuming you showing the daemon for 4.3+ to show folks how they could store credentials of a type other than RSA correct?

Since the daemon still requires the user to enter a pin on 4.3+ do you think the 'Correct' approach would be:

1. Generate RSA and AES keys based on some (different) user input.
2. Wrap the AES key using the RSA Key
3. Store the RSA key in keystone via:
4.0-4.2.2 - Use the Daemon (forces an OS level pin)
4.3 + - Use the Android Keystore (no OS level pin needed)
4. Store the wrapped AES key .... where?

I'm no where near a security expert - what I'm curious about is how secure is just wrapping the AES key using the RSA key (using the Cipher.WRAP_MODE with "AESWrap" - which I think is http://www.ietf.org/rfc/rfc3394.txt) and storing that where it is easily found. Somewhere like say, SharedPreferences which is just a plaintext file.
Nikolay Elenkov said…
Yes, I should've tested it on 4.3. I'll fix it when I get a chance.

It would be better to use the officially supported API and only use RSA keys on 4.3 (or EC on 4.4). You can wrap the AES key with the RSA one and then store it anywhere, preferably as a private file in your app's directory. As long as other apps cannot get the private key, you should be OK. Here's an example from Google:

https://android.googlesource.com/platform/development/+/master/samples/Vault/src/com/example/android/vault/SecretKeyWrapper.java

If you are using the daemon/service directly you can just store the AES key directly (as in my sample app), it will be encrypted on disk.
Nikolay Elenkov said…
I've updated the sample app to work on both 4.3 and 4.4.
서석충 said…
Thanks for your comprehensive explaination. Could I ask some questions?

1. Can I store the EC key pair at the keystore by using the IKeyStoreService as you store the symmetric key at the keystore?

2. In the process of generating RSA key pair with KeyPairGeneratorSpec in your example, is the private key encrypted even if the ".setEncryptionRequired()" is not called?

3. The keys in keystore are encrypted with the master key, right?. When I call the keyEntry.getPrivateKey() function, is the returned private key in plain form? Is it not necessary to provide password information to get the private key?

4. Can I add user-generated key to the keystore with setKeyEntry function?

Nikolay Elenkov said…
EC keys are officially supported in 4.4, so you don't have to resorts to such tricks. Keys are encrypted by default when stored on disk. When stored in hardware, it depends on the implementation. You cannot extract the private keys, only use them for signing (or 'raw' encryption). setKeyEntry() should import your keys in the key store, just like the system does with PKCS#12 files.
서석충 said…
Thank you for your response.
Actually, I want to use EC on devices lower than 4.4. Thus, I think that it is required to store the private key with being encryted by password or trickly using keystore.
You said that "You cannot extract the private keys". But, the code below tries to get the
private key without providing any password or encryption key.

RSAPrivateKey privKey = (RSAPrivateKey) keyEntry.getPrivateKey();

Do I understand right?

Nikolay Elenkov said…
'Extract the private key' means extract the key material (raw key bytes). The RSAPrivateKey is just a reference, you cannot save it to a file, for example.
David Bauer said…
I think that the problem is the used Key, I tested now the same function with how you produce the key with Crypto.generateAesKey(); and then getEncoded() and now get don't return null anymore, is this expected or could it be a bug?
David Bauer said…
Hello Sir, thank you very much for sharing this all. I am encountering a problem with an implementtion now based on your code, if i call following code it works on Android 4.4 but on Android 4.3 get returns null, do you have an idea why?:

sKeyStoreService.insert("jbase", new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, -1, 1);
if (0 <= sKeyStoreService.exist("jbase", -1)) {

// TODO: why is this null on android 4.3?
final byte[] test = sKeyStoreService.get("jbase");

if (test == null) {
Log.d("+++", "+----------------------------------------------------");
}
}

I am using 2 equal Nexus 7, one with 4.3 and the other with 4.4.

(Update) -> I tested it now with a key generated by Crypto.generateAesKey().getEncoded() and it works now, I don't understand how the content of the key can affect the get method?
Nir Avnery said…
Hi Nikolay,

I've been following all of your articles in the field of credentials storage and I find them all very helpful !

I'm trying to better understand a question which was already asked by one of your readers: is it possible to use a private key stored in the credentials storage to decrypt data somehow ? I understand the private key never leaves the hardware and it can be used to sign data... but can it be used to decrypt data as well ?

Thanks !
Hi Nikolay,

First of all, congratulations about this (and others) posts related to the Android Security, you cover the internals not documented (or not well documented) by Google, very usefull! Thanks for sharing.

Could you please help me to clarify two questions about the new KeyStore in Android 4.3?

Is it right to say that:

1. With the new "AndroidKeyStore", after storing a key through the setKeyEntry(), you'll not anymore be able to get this key in the encoded form - you'll always get null in key.getEncoded() ?

2. And there's no other way to recover (programmatically export) the keys from the own Application ?


Thank you.

Regards.

Eduardo Piovesam
Jay Su said…
Thanks for the useful posts.Can an encrypted password in the App be saved in the device using KeyChain API . I understand that this works in V4.3 but does it work in ICS.
androido said…
Hi Nikolay,
Thank you for this great post.
I was wondering, you say that root or system cannot access the keys of other users,
but couldn't root use setuid or something like that to impersonate a user and then retrieve & use its key?
Thanks!
Hi Nikolay and thanks a lot for this post.

By the way, i'm still a little bit confused between keychain and keystore API on Android 4.3. I mean do the keys put in the android keystore are hardware-backed or only credentials put in keychain are hardware-backed? It's not clear to me when reading the shorts sections in Android APIs and i'm quite a beginner on this topic.

My second problem is about: i'm not sure to well understand the behavior when the lock screen PIN is changed by the user. Do all the keys of all applications using the android keystore are wiped ? this behavior confuse me a lot. Can you confirm ?

Regards
Nikolay Elenkov said…
Changing the PIN does not delete keys, it merely re-encryptes the master key. See other articles about credential storage for details.
Nikolay Elenkov said…
Of course, a root user can do anything. A process running as root however is may not be so clever though.
Nikolay Elenkov said…
Generally it works on all recent versions, but only 4.3 offers a proper API. See earlier posts on the topic and sample code for details.
Nikolay Elenkov said…
You can use the sample code to experiment about 1. If the key is generated inside the keystore you cannot get it in encoded form. As for 2, no, there is no API to export keys and the implementation specifically doesn't allow it. If you have root access and know the pin password you can recover the keys though, unless it is hardware protected.
Nikolay Elenkov said…
You can encrypt/decrypt data with RSA keys (see sample code), but the usual size limits apply. You can however use an RSA key to wrap a symmetric (AES, etc.) key and use that to encrypt as much data as you want.
Nikolay Elenkov said…
If you put a key blob into the keystore using the put() method you can retrieve it later. If you generate the key in the keystore, you can only use it for signing, but not export it.
Dorian Cussen said…
Amazing post and many thanks for your efforts. I notice that your cert generation does not work on a hardware keystore enabled device due to a few lines that try to generate and access key pairs and private keys. Looking at your github keystores for 4.3+ I can see your comments

* @hide This should not be made public in its present form because it
* assumes that private and secret key bytes are available and would
* preclude the use of hardware crypto.

is there a current solution for hardware devices? Its strange that methods like `kpGenerator.generateKeyPair()` are used to generate, store and return the keypair - as this now cannot be used without an IllegalStateException.

Any pointers would be much appreciated. My goal is to generate a local key pair and use the public key for encrypting a locally stored AES key which can then be hardware decrypted using the stored private key.

Many thanks!
David said…
Hi Nikolay and Nir Avnery,

I am wondering the same thing. Your article was very helpful. However, I can't seem to achieve my objective: encrypting and decrypting data with a RSA public key and private key, respectively. I used your example code above to generate and store the keys using the hardware-backed "AndroidKeyStore". Encryption is successful, but when I attempt to decrypt I receive this error:

java.lang.UnsupportedOperationException: private exponent cannot be extracted
at com.android.org.conscrypt.OpenSSLRSAPrivateKey.getPrivateExponent(...)

I am unsure with what I am doing wrong, or if this is the correct consequence of storing the private key in the TEE. If this is the correct consequence, then what is the purpose of storing a private key in hardware if you can never use it?

Thank you
Nikolay Elenkov said…
Those comments are from the Android source, the project simply includes the file with a few modifications. The latest Github code does work on a Nexus 5, not sure what modifications you made. I'll test it on a N4 as well, but generally should work.
Nikolay Elenkov said…
What code exactly did you use? The sample project shows how to do encryption/decryption with OAEP padding. Also see the Vault linked in one of the previous comments for how to use RSA keys to wrap an AES key.
Nikolay Elenkov said…
Works fine on Nexus 4, Android 4.4.2
David said…
Thank you for entertaining my questions.

Following the example code provided in your post under the section "Public API"

KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
....
RSAPublicKey pubKey = (RSAPublicKey)keyEntry.getCertificate().getPublicKey();
RSAPrivateKey privKey = (RSAPrivateKey) keyEntry.getPrivateKey();

Once I retrieve the key pair, I simply wanted to test encrypt and decrypt operations. The below code is to decrypt. However, the line marked with "<---" causes the error I wrote in my initial post trying to use the privKey.

private static byte[] decodeData(Key key, byte[] data, String transformation) throws Exception
{
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.DECRYPT_MODE, key); <-----
byte[] decrypted = cipher.doFinal(data);
return decrypted;
}

This generating the error:
java.lang.UnsupportedOperationException: private exponent cannot be extracted
at com.android.org.conscrypt.OpenSSLRSAPrivateKey.getPrivateExponent(...)

This error seems to imply that once you generate or store a key in hardware, that you can not ever retrieve it to perform operations with it such as decrypting.
Nikolay Elenkov said…
Yes, you cannot retrieve the raw key bytes, this is by design. However you can still use the key for signing/encryption, as long as you use the built-in AndroidOpenSSL provider. As for your code, whether it works or not very much depends on the 'transformation' string. If it is a transformation supported by the AndroidOpenSSL provider, it will work. If not, you will get another provider (most probably Bouncy Castle) which cannot use keys without accessing the raw key material, and you get an error. The '"RSA/ECB/NoPadding" transformation should work fine, that's what my sample app uses. This transformation is an RSA primitive operation, so you can build anything else on top of it (signature, scheme, etc.). Again, see how to sample project uses it to implement RSA-PSS.
Hi Nicolay,
Thank you for all the explanation. I am trying to configure EAP TLS on KitKat 4.2.2. Can you please explain how to set the client and server certificates.
andrea loffredo said…
Hi,
thank you for the post.
I've made some test on my app and I've found that the keystore is not a lot secure because it is true that each app have the own private keys but if I make an app with same package I'm be able to recover the keys of other apps.
I have made some mistake or is it true ?
Beside that I found that if the app is deleted the keys are still in the keystore and can be recover with an app with same package.

Thanks for your time.
Nikolay Elenkov said…
Not sure exactly what you did, but if you create an app with the same package name and signature it is effectively the same app. Uninstalling the app should delete any keys it has created, if that is not happening it might be a bug in your device's Android version. How did you check that keys are still in the keystore after you uninstall the app?
andrea loffredo said…
Hi,
it is exactly the same thing that I have thought, of course if two app have same package and signature it is effectively the same app but I have tried to sign the second app with another certificate and this app can see the keys.

For your question, I have tried to uninstall the app and reinstall it and the reinstalled app can get the key.

My device is the galaxy 3 with Android 4.3.

Many thanks.
Nikolay Elenkov said…
I've heard that Samsung have a somewhat different implementation of credential storage, but it's somewhat unlikely that they let you see other app's keys. Are you sure you didn't just generate new keys with the same names for the second app?
andrea loffredo said…
Yes, you are right!! I have tried with a nexus 5 and the keystore works as you say in your post.
The keys are removed due to uninstall process and since it is not possible to install app with same package but different certificate I am not be able to recover the keys
However on Samsug s3 the keys are not removed, I think this is a security issue of Samsung device.

Thanks a lot for your time.
androido said…
thanks for replying.
So if root can setuid to another user and get its keys, how is it true to say that even root cannot access those keys as you said in your post?
Nikolay Elenkov said…
If the keys are hardware-protected, setuid/root is not enough to extract them. You have to compromise the hardware or trusted OS to get access to protected keys. As this is a whole different, lower level OS, root has no meaning.

Comparable (although a bit less secure) to a smartcard -- you can analyze and attack it if you have physical access, but you cannot extract keys (unless you have some very expensive and specialized equipment)
androido said…
But doesn't the mechanism eventually have to rely on the uid requesting the key from the keystore (hardware based or not)?
Nikolay Elenkov said…
Using a key and extracting key material are different things. Do read this and other credentials storage articles for some background.
kycera said…
So if i wrap my symmetric keys with KeyStore RSA, root user is able to unwrap them ? (use RSA keys)
lespaul49 said…
Hi,

I've exactly the same question. I've managed to decrypt some data successfully with a private key stored in hardware, i.e. a key generated with the AndroidKeyStore provider in the same way as explained in this article. My phone is a Nexus 4 with Anroid 4.4.

See the code below how decryption can be done. I wonder what exactly happens in this case. According to the article and other sources, the private key can not be extracted from hardware. However, I use another provider ("AndroidOpenSSL") for the decryption which (I think) means that the decryption is not done from hardware.

How is this possible?

KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry("keyalias", null);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
cipher.init(Cipher.DECRYPT_MODE, privateKey);
cipher.doFinal(data);
Nikolay Elenkov said…
Exactly the same answer: using the key != extracting the key. The AndroidOpenSSL provider uses an OpenSSL engine that can take advantage of the keymaster module, which in turn can access (but not export) the keys. See other posts on credential storage for details.
peterson said…
This comment has been removed by the author.
Stephen Wilcox said…
Hi Nikolay,

Is it possible in 4.4 to augment the Android keystore with your own implementation, for example, to a SE embedded in a microSD?
Nikolay Elenkov said…
Only if you create your own Android build.
Brian said…
I've been trying to run your application (from GitHub) on a Samsung S3 on JB 4.1.2. While the AES test works just fine, Sign/Verify PSS and the Encrypt/Decrypt OAEP tests fail due to the lack of the KeyPairGeneratorSpec and related classes. Apparently these were added in 4.3 and are not present in earlier versions.

Of course, that isn't all that is missing. If I were to "lift" KeyPairGeneratorSpec from AOSP and place it in your test app (along with IKeyStoreService...), I then get NoSuchProvider exceptions complaining about the lack of AndroidKeyStore.

So when you (and others) say that this works on older versions of Android are you just commenting on that the KeyStore functions work or are all of the test functions working? I guess it is possible that Samsung's 4.1.2 release ripped out the AndroidKeyStore provider where others haven't but I get the same error when I run on the emulator using versions 4.1.2 or 4.2.2.

On ICS, you disable all of those buttons. In fact, you disable these buttons when the current OS build is less than JB - I see that in toggleControls and the activity's findViews method. My experience would suggest that it should be checking for releases >= than JB43 but I have limited experience (one S3 running 4.1.2, one Nexus 5 running 4.4.2, and a bunch of emulator types for JB, ICS, & KK). If I'm correct, it is an easy fix to your code in the git repo.

What exactly does the "backwards compatibility" buy? I presume the point is that it provides a means to save symmetric keys (which you say in your post). Is this inherently more secure than encrypting a key and storing it in a file? I guess the answer again is how that key is encrypted.

In your reply to Brian Deblanc's comment, you point to a Google example using RSA keys to wrap an AES key and you also state that he could just store the AES key via the keystore service. Is one way better than the other? The Google example won't work on anything less than JB4.3 AFAICS. If you have to support old and new OS, what's the best approach? Is it best to handle it one way on JB4.3+ (use RSA) and the other (AES via your KeyStore service design, encrypted key in a file, ...) on older versions of Android?

Your examples are really good and greatly appreciated. I'm just searching for the best solution.
Nikolay Elenkov said…
The sign/verify operations were added in 4.1 and can technically be used via the private API (KeyStore.sign(), etc.) The app doesn't demonstrate that, but it should be easy to add. If you decide to use those private APIs you don' t need KeyPairGeneratorSpec and friends, but you need to copy some of its functionality (simply dropping the file doesn't work).

As for general strategy, using the official APIs is best, and on versions that don't have official APIs (4.1 and 4.2), the private APIs may or may not available, and may or may not work (at all or as expected). Use at your own risk, if you decide you must.

What this buys you is that you get to use OS protection instead of rolling your own, at the expense of some risk. You can achieve the same thing by deriving a key from a user-supplied password and storing encrypted keys, etc. in your app's private directory. The user will have to enter their password each time they start your app (you can also cache derived keys to make this less painful), whereas Android does the whole key decryption thing when the lockscreen is unlocked.
Ash Mishra said…
With API 19, you can now set a minimum key size for the spec

KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias("key1")
.setKeySize(4096)
...

Iman Biglari said…
Hi Nikolay

Thanks for your nice article.

I'm getting an exception when trying to retrieve the generated key pair on this line:
PrivateKeyEntry keyEntry = (PrivateKeyEntry) keyStore.getEntry(RSA_KEYS_ALIAS, null);
The exception text says "chin == null"

Can you please tell me what I'm doing wrong?
Oud Player said…
Hi Nikolay,

Sorry for the simple question but even with all the comments above I don't understand what modifications should be done to support hardware backed based Keystore. What keystore API should the vendor handle? Where can I find the API's list that should be handled. Who should write the wrapper to connect Android keystore routines to vendor TZ applications?

By the way, Are there other feature that Google may want to leverage with Trustzone?

Thanks for he help.

Fabrice.
Nikolay Elenkov said…
The HAL interface is called keymaster, you can find it in AOSP. Look at system/security/softkeymaster/ for the default implementation. See the previous article on the subject for some more details:
http://nelenkov.blogspot.jp/2012/07/jelly-bean-hardware-backed-credential.html

Typically vendors are responsible for writing the HAL 'glue' . Most devices implement DRM using TZ, it's actually the primary use case.
Martin said…
This comment has been removed by the author.
Martin said…
This comment has been removed by the author.
Martin said…
Hi Nikolay,

I am following you since a few moment due to all interesting articles you wrote about Security, especially about Secure Element access for NFC purposes. I bought also your book which is very interesting and easily understandable.

But today, I am facing to a problem I don't understand at all.

I am using the KeyStore API, to generate KeyPair, and access the public key or private key with this method :
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
Log.w(TAG, "getPublicKey() Not an instance of a PrivateKeyEntry");
}
PublicKey pub = ((KeyStore.PrivateKeyEntry) entry).getCertificate().getPublicKey();

This is pretty well working on my Nexus 5, but with another N5, it is only working for a certain time, after it stops working and I have the following line in my logcat console :
W/keystore : Could not read CACERT_myalias
Could not find anything about that on Google, so any idea about what can cause this ?
Oud Player said…
Hello Nikolay,

I am trying to run you application on my QC based platform.
This platform supports trustzone and Google keymaster_test is working ok and triggers the QSEECom driver.

While using your application I can key that keys are created in \data\misc\keystore but I cannot see that the QSEECom driver is triggered.
I took care to replace the keystore.default.co in \system\lib\hw but still I cannot see that the TrustZone application is triggered.

So you have any clue what I can miss here?

Thank you.

Fabrice.
Nikolay Elenkov said…
What kind of keys does this platform support? Generating and using AES keys won't trigger the QSEE, you probably want RSA keys. If that doesn't work, you might need to debug the platform.
Nikolay Elenkov said…
Not sure, you might be hitting some bug in the keystore implementation. Are both N5s using the same Android version?
Martin said…
Hello Nikolay, I've discovered the reason about that. It happens when the user has lockscreen security feature enabled. When you change the security pin code or whatever, it changes the RSA keys as well... This is really annoying ... Bad implementation you think so ?
Nikolay Elenkov said…
This comment has been removed by the author.
Nikolay Elenkov said…
It is a bug, see https://code.google.com/p/android/issues/detail?id=61989 and
http://jbp.io/2014/04/07/android-keystore-leak/
Oud Player said…
Well, according to the log below, it seems that RSA keys is supported:
D/KeystoreActivity( 3044): Keystore state: UNLOCKED
D/KeystoreActivity( 3044): RSA supported true
D/KeystoreActivity( 3044): RSA bound true
D/KeystoreActivity( 3044): DSA supported true
D/KeystoreActivity( 3044): DSA bound false
D/KeystoreActivity( 3044): EC supported true
D/KeystoreActivity( 3044): EC bound false
D/KeystoreActivity( 3044): Keystore state: UNLOCKED

I can also see the 2 keys in the \data\misc\

It seems that you application and the Google Keymaster_test are using 2 different API levels. The Keymaster_test uses QSEECom driver.
The question is where is the decision to run Keystore TZ-based or not (SW-based) located? By the way, your application did detect the plaform to support HW-backed.

Fabrice.
Oud Player said…
Nikolay,

It seems according to the log below that RSA keys is supported:

D/KeystoreActivity( 3044): Keystore state: UNLOCKED
D/KeystoreActivity( 3044): RSA supported true
D/KeystoreActivity( 3044): RSA bound true
D/KeystoreActivity( 3044): DSA supported true
D/KeystoreActivity( 3044): DSA bound false
D/KeystoreActivity( 3044): EC supported true
D/KeystoreActivity( 3044): EC bound false

The point is that Keymaster_test google application uses the QSEECom driver API straight. Thsi is probably why I can see the TZ triggered.
You application uses Keystore API and I cannot see TZ triggered even using RSA key and even the application detected that the platform supports HW-Backed.
So the question is: Where is the decision in the Android framework to use HW-backed or not located? I believe that I may fail in that decision.
By the way, the fact that AES keys is not stored HW-backed is due to the keystore module or due to your application?

Fabrice
Nikolay Elenkov said…
If the test is hitting QSEE directly, it all makes sense. To get the Java APIs to route to QSEE you need to have a proper keymaster module implemented and hooked up via the OpenSSL engine, see the implementation in AOSP for details. Generally, if you have a hardware specific module, like keystore.msm8974.so, it *should* be picked up and used automatically.

As for AES, the keymaster HAL only supports asymmetric keys ATM, so there is no way to generate (or store) AES keys in hardware.
Oud Player said…
Nikolay,

It seems according to the log below that RSA keys is supported:

D/KeystoreActivity( 3044): Keystore state: UNLOCKED
D/KeystoreActivity( 3044): RSA supported true
D/KeystoreActivity( 3044): RSA bound true
D/KeystoreActivity( 3044): DSA supported true
D/KeystoreActivity( 3044): DSA bound false
D/KeystoreActivity( 3044): EC supported true
D/KeystoreActivity( 3044): EC bound false

The point is that Keymaster_test google application uses the QSEECom driver API straight. Thsi is probably why I can see the TZ triggered.
You application uses Keystore API and I cannot see TZ triggered even using RSA key and even the application detected that the platform supports HW-Backed.
So the question is: Where is the decision in the Android framework to use HW-backed or not located? I believe that I may fail in that decision.
By the way, the fact that AES keys is not stored HW-backed is due to the keystore module or due to your application?

Fabrice
Oud Player said…
Sorry Nikolay, this is the answer to your previous comment. Seems that there is a problem if I submit it in the Reply field.
================================================================================
Nikolay,

It seems according to the log below that RSA keys is supported:

D/KeystoreActivity( 3044): Keystore state: UNLOCKED
D/KeystoreActivity( 3044): RSA supported true
D/KeystoreActivity( 3044): RSA bound true
D/KeystoreActivity( 3044): DSA supported true
D/KeystoreActivity( 3044): DSA bound false
D/KeystoreActivity( 3044): EC supported true
D/KeystoreActivity( 3044): EC bound false

The point is that Keymaster_test google application uses the QSEECom driver API straight. Thsi is probably why I can see the TZ triggered.
You application uses Keystore API and I cannot see TZ triggered even using RSA key and even the application detected that the platform supports HW-Backed.
So the question is: Where is the decision in the Android framework to use HW-backed or not located? I believe that I may fail in that decision.
By the way, the fact that AES keys is not stored HW-backed is due to the keystore module or due to your application?

Fabrice
Oud Player said…
Nikolay,

It seems according to the log below that RSA keys is supported:

D/KeystoreActivity( 3044): Keystore state: UNLOCKED
D/KeystoreActivity( 3044): RSA supported true
D/KeystoreActivity( 3044): RSA bound true
D/KeystoreActivity( 3044): DSA supported true
D/KeystoreActivity( 3044): DSA bound false
D/KeystoreActivity( 3044): EC supported true
D/KeystoreActivity( 3044): EC bound false

The point is that Keymaster_test google application uses the QSEECom driver API straight. Thsi is probably why I can see the TZ triggered.
You application uses Keystore API and I cannot see TZ triggered even using RSA key and even the application detected that the platform supports HW-Backed.
So the question is: Where is the decision in the Android framework to use HW-backed or not located? I believe that I may fail in that decision.
By the way, the fact that AES keys is not stored HW-backed is due to the keystore module or due to your application?

Fabrice
Nikolay Elenkov said…
Not sure why you are posting the same thing 3 times, but see my comment above. You need a properly named hardware-specific module for this to work
Does keys store in same location for both SW keymaster and HW keymaster implementation.
/data/misc/keystore.

Is this path deletes during factory reset.

Thanks/Rama.
Nikolay Elenkov said…
This comment has been removed by the author.
Nikolay Elenkov said…
Yes, but what exactly the files contain depends on the implementation when backed by hardware. It might just be an ID, and not actual key material (encrypted or not). If the actual keys are stored in a different partition or in the hardware itself (say SE), a factory reset might not clear them (but you won't be able to extract).
Kapil said…
Hi Nikolay,
Nice array of post, looking forward to the book. I wonder if there is an straightforward way of storing users username/password type of credential (not key/certificates) in android for an app. iOS seems to provide a simple yet effective solution in form of KeyChain (and now TouchId is also opening up). For Android 3 potential candidates i.e. AccountManager, SharedPreferences & Keychain seem to serving other usecases and not the regular username/password. What do you advice for apps which just want username/password to be stored for apps and device taking care of the encryption and access control (with different vectors of attacks possible) on these credentials.
I might be missing something obvious but i felt this is so common a usecase where apps want to store these username/password type of credential for the app without anyone else (other than the user and the app) knowing about it.
Nikolay Elenkov said…
You probably want AccountManager for accounts, but keep in mind it doesn't encrypt on disk. The stock email client use this also to store email credentials. AccountManager is not really a security measure, but useful for background sync, etc. Also easier to migrate if you decide to switch to OAuth and the like.
Martin said…
Sorry for late reply, thanks for sharing this, I hope this will be fixed in next Android release. In the meantime, do you have any suggestion of other solutions to save sensitive data on the device ?
Nicolas Sollier said…
Hi Nikolay,

Amazing post ! Thanks for sharing !

I am working in a company specialized in NFC and obviously realized the potential of HCE when it was released with Android Kitkat.
However, we first noticed the lack of security of HCE compared to card emulation applications based on an cardlet in a SIM Card (Such as Calypso application).

But after having read your post, I wonder if that would be possible to have an application with high level of security (equivalent to an cardlet) by storing private keys in the hardware.

My first question is, Do you know if all recent mobiles (I mean released this year and with Android > 4.3) support hardware storage ? If not, could you explain me what are the hardware requirements ?

Second, if the mobile does not support hardware storage for any reason, are there real risk for the keys security using non hardware storage ? (the hidden question is, Can we think of a real secure HCE application massively deployed like transport application?)

Thank you !
Nikolay Elenkov said…
It really depends on your threat model. If getting your shared keys leaked from a single device has the potential to bring down the whole system, you might want recondiser your design and/or include countermeasuers.

'Hardware-backed' key storage is currently implemented as a TrustZone trusted app in pretty much all major devices, so it is theoretically possible that keys can be leaked due to an implementation flaw (several have already been found). See this series of articles for a detailed comparison of the security level offered by HCE versus SE: http://randomoracle.wordpress.com/2014/03/08/hce-vs-embedded-secure-element-comparing-risks-part-i/
Nicolas Sollier said…
Thank you for your quick answer. I read all the articles you mentionned and learnt a lot on the security mechanism.

Do you know how many different TrustZone implementation exist ? (I suppose one per chip manufacturer) ?
Nikolay Elenkov said…
You probably mean TEE implementations. I don't know how many exists, but the 3 major ones cover almost all mainstream devices: MobiCore, Quallcomm SEE, Trusted Foundations (by TrustedLogic).
Nicolas Sollier said…
Yes I meant TEE. I have to try it, but I think HCE combined with private keys stored in a TEE can have a sufficent level of security for many applications.

Thanks again for your time.
yogesh said…
Hi Nikolay,
I am using AndroidKeyStore in my device admin application to store application's Public-Private key pair. I have shared public key with server and have used private key to encrypt shared prefs data.

Now, issue I am facing is when user changes device password, all keystore related files will be deleted. To fix this issue, I cache key-pair in RAM and after device password change, I tried to use keystore.setKeyEntry(), but no luck.

How can I put back existing key-pair back to android keystore ?
How can retain existing key-pair after device password change?
Can you please help me out in fixing this issue ?

If this is android default behaviour, what would be the way to secure application data even from rooted user ?
Baì14 said…
Hello Nikolay,
thank you so much for sharing your know-how.
I'm using code in sample https://android.googlesource.com/platform/development/+/master/samples/Vault/src/com/example/android/vault/SecretKeyWrapper.java to store a generated RSA key pair in the Android KeyStore, but when I execute the method unwrap I get the exception IllegalArgumentException: key.length == 0. Debugging the app I noticed that the instruction mPair.getPrivate() returns an object, but executing mPair.getPrivate().getEncoded() the result is null. I have this problem both on Android 4.4 and on Android 4.3.

Could you help me, please? Thanks a lot!!
Filippo
Nikolay Elenkov said…
If the keystore is hardware-backed, you cannot extract the private key via getEncoded(). You shouldn't need to though, you can encrypt/decrypt without extracting the key. Why do you call getEncoded() in the first place? The vault sample doesn't seem to.
Baì14 said…
Thanks for the answer Nikolay.
I was executing the instruction mPair.getPrivate().getEncoded() just for debugging purposes. The code I use is exactly the same in the sample. My problem is the exception I get when the unwrap is executed (at line 112 in the sample). I post an extract of the stack trace:

java.lang.IllegalStateException: Could not execute method of the activity
[...]
Caused by: java.lang.IllegalArgumentException: key.length == 0
at javax.crypto.spec.SecretKeySpec.(SecretKeySpec.java:62)
at com.android.org.conscrypt.OpenSSLCipherRSA.engineUnwrap(OpenSSLCipherRSA.java:333)
at javax.crypto.Cipher.unwrap(Cipher.java:1409)
at com.example.android.vault.SecretKeyWrapper.unwrap(SecretKeyWrapper.java:112)

I have the problem both on a device with hardware-backed keystore and on a device with software-only keystore encryption.

Thank you.
Filippo
Nikolay Elenkov said…
Sounds like the unwrapped key is 0 bytes long. This could be due to a bug in the app (or the platform). You'd better use a debugger/printf and check what exactly goes into SecretKeyWrapper.unwrap()
Dave Smith said…
Do you know the format of the files stored in '/data/misc/keystore/user_N'?
After extracting them from the device, with my limited experience, openssl doesn't seem to recognize them as a private key and an X.509 certificate.

I can't tell if these contain the actual key data, as they also seem to be generated for keys that should be stored in a hardware-backed container.
Nikolay Elenkov said…
Those are encrypted blobs (even certificates), you need to decrypt them first in order to get the data. This may not be possible if the keystore is hardware backed. Here's the format, look in keystore.cpp for details:

struct __attribute__((packed)) blob {
uint8_t version;
uint8_t type;
uint8_t flags;
uint8_t info;
uint8_t vector[AES_BLOCK_SIZE];
uint8_t encrypted[0]; // Marks offset to encrypted data.
uint8_t digest[MD5_DIGEST_LENGTH];
uint8_t digested[0]; // Marks offset to digested data.
int32_t length; // in network byte order when encrypted
uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE];
};
Beowolf said…
Hi Nikolay,
Thanks for some of the most informative content I have seen. I like to ask if there has been any change in the level of access and interface with the hardware. What I mean is I do not understand why we are only limited to hardware supported key creation and verification. It is my understanding that ARM architecture provides for a number of instructions, and I do not see what would prevent me from trying to implement them. I do realize that I am still limited to what the vendor provides. In my case, I have a msm8974, and the associated build environment from source. After reading the truly amazing content above, I did a search in my environment, and see that I have acess to some qsee files as follows:
~/WORKING_DIRECTORY$ tree | grep -i 'qsee'
│   │   │   │   ├── qseecomi.h
│   │   │   ├── qseecom
│   │   │   │   └── qseecom.txt
│   │   ├── qseecom.c
│   │   ├── qseecom_kernel.h
│   │   ├── qseecom_legacy.h
│   │   ├── qseecom.o
│   │   │   └── QSEEComAPI.h
│   │   ├── qseecom.h

I do not see a qseecomlib.so. I think it should be possible to implement the arm TEE instructions such as SMC using assembly, and compile with ndk.
Nikolay Elenkov said…
Those are just the GPL-licensed part that provide the kernel interface. The actual trusted application that provides key management and what not is not open source. Neither is the interface library (qseecomlib.so). You could easily reverse engineer the interface library based on kernel code, but that doesn't really buy you that much. Even if you implemented your own secure application, you cannot deploy it in the TEE of a commercial device. If you want to experiment with TrustZone/TEE, get the USB Armory device, it's unlocked and comes with SoC documentation from Freescale.
Beowolf said…
Hi Nikolay,
I immensely enjoyed and learned from this article as well as every other one you had so far. I wanted to check with you to see if anything has changed as far as methods of interfacing with TEE. I built an image for my Samsung Note 3, which as you may know has the Qualcomm Snapdragon 8974. What I want to ask you is what would prevent me from writing the assembly code to issue commands to Secure environment? It sounds to me, and perhaps I need to read your article again, you say it is not possible to interface with the QSEE.
Raphael Cohen said…
Thank you for your article that helped me a lot !

I have a little question, is it possible to store a public key in the keystore. In the method that I see we can store a Certificate or a PrivateKey but I havn't seen anything about storing a public key ...
ramprasath said…
hi all i want store my own key and when uninstall and reinstall identify that same key how to do
If I have root access, can I access the TEE to sign a document with any application's keys stored in the TEE?
Hi!
I am a trainee in a SIM Card based application solution providing company.
I want to know is that possible with mobile handset to establish the connection with server without any usage of SIM card. In detail is it possible:
1. Mobile Device can establish a secure session with Server
2. If yes than it should be possible without SIM Card usage. Some information can be used by Mobile device from SIM Card.
3. Mobile Device can download the data and save it.

I hope i made my point clear. Please get back to me.
Kanna said…
Hi Nikolay,
I am following your blog regularly and I am using the sample to store key and values to android keystore(used your sample code).And it is working fine till Lollipop but It is not working in Android M. Can you please suggest me the way how to store KEy and value to Android Keystore in Android M . I saw so many examples to store key in Amdroid M but not as a Key and Value.. Please help to get out of this.
Goi said…
Hi,
I'm trying to understand the key blobs that are stored in /data/misc/keystore/user_X. From what I understand, even in hardware-backed keystores, the actual keys are actually stored here, but somehow encrypted (several times?) There are options to disable encryption (e.g. with setEncryptionRequired()/setUserAuthenticationRequired()), presumably there are still other encryption layers that protect the private keys in this case? Can you describe/explain how private keys are stored within the key blob, what keys are involved in encrypting what data? I'm a bit lost even after reading your piece (including the Android M update)
Nikolay Elenkov said…
If your device has a hardware-backed keystore, keys will always be encrypted with a device-specific key,
which is not directly accessible to Android (it's in the TEE). If you call setEncryptionRequired(true),
keys will further be encrypted with a key derived from your PIN/password. This has the side effect that
such keys will be deleted when you change your PIN/password.

If you are interested in the details, have a look here:
https://bits-please.blogspot.jp/2016/06/extracting-qualcomms-keymaster-keys.html

The 'KeyMaster keys' the blog talks about are also used to encrypt keystore key blobs.

Popular posts from this blog

Decrypting Android M adopted storage

Password storage in Android M

Unpacking Android backups