Droidcedas : Storing Application Secrets Inwards Android's Credential Storage

This article describes how to utter to the arrangement keystore daemon remove as well as shop app-specific secrets inwards the arrangement credential storage. It volition innovate mortal API's, non available via the Android SDK as well as some OS services implementation details. Those may modify at whatever time, as well as are non guaranteed to work. While the techniques described possess got been tested on a few dissimilar devices as well as OS versions (2.1 to 4.0), at that topographic point are no guarantees. Use caution if yous determine to implement them inwards a production app.

As described inwards previous articles, Android has had a system-level credential storage since Donut (1.6). Up until ICS (4.0), it was solely used yesteryear the VPN as well as WiFi connector services to shop mortal keys as well as certificates, as well as a world API was non available. ICS introduced a world password-based encryption article, 1 option is to derive a substitution from a user-supplied password as well as work it to encrypt sensitive information mortal to an application. While this works, it requires the user to think 1 to a greater extent than password, as well as increases application complexity -- developers postulate to implement services, non remove related to app functionality; services that should ideally last provided yesteryear the system. The adjacent Android version, reportedly simply unopen to the corner, mightiness reveal such services via world API's, but yous could work them now, if yous are willing to possess got the adventure of your app breaking when Jelly Bean comes along.

Android's credential storage is implemented every bit a native Linux service (daemon), alongside a few extra layers on top of it that larn inwards available to the framework. Let's chop-chop review what nosotros know close the keystore daemon (described inwards to a greater extent than special here):
  • it's a native daemon, started at boot
  • it provides a local command socket to allow apps as well as arrangement services to utter to it
  • it encrypts keys using an AES 128 flake principal key
  • encrypted keys are stored inwards /data/misc/keystore, 1 file per key
  • the principal substitution is derived from the device unlock password or PIN
  • it authorizes management commands execution as well as substitution access based on caller UID
Here's a quick summary of the available commands as well as who is permitted to execute them:

Keystore daemon commands
Command Description Allowed UIDs Parameters
test Check that the substitution shop is inwards a usable state anyone but root, vpn as well as wifi none
get Get unencrypted key anyone (*1) key name
insert Add or overwrite key anyone but root, vpn as well as wifi key call as well as value
del Delete a key anyone but root, vpn as well as wifi (*1) key name
exist Check if a substitution exists anyone but root, vpn as well as wifi (*1) key name
saw List keys alongside the specified prefix anyone but root, vpn as well as wifi (*1) key prefix
reset Reset the substitution store system none
password Change the substitution shop password system new password
lock Lock the substitution store system none
unlock Unlock the substitution store system none
zero Check if the substitution shop is empty system none
*1 Only keys created alongside the same UID are visible/accessible

As yous tin reckon from the tabular array above, 1 time the credential storage is initialized as well as unlocked, whatever app tin add, delete, listing as well as larn keys. Each substitution is outflow to the UID of the procedure that created it, so that apps cannot access each other's keys or the arrangement ones. Additionally, fifty-fifty arrangement apps cannot reckon app keys, as well as root is explicitly prohibited from creating or listing keys. Thus, if the API were world user apps could work the credential storage to securely shop their secrets, every bit long every bit it is unlocked. Unlocking, however, requires a arrangement permission. On ICS, the credential storage is unlocked when yous come inwards your device unlock pattern, PIN or password, so inwards practise the keystore daemon volition last already inwards an unlocked Earth yesteryear the fourth dimension your app starts. On pre-ICS devices the device unlock password as well as the credential storage protection password are separate, so unlocking the device has no number on credential storage state. Fortunately, Android provides a arrangement activity that tin unlock the substitution store. All nosotros possess got to create is ship an intent alongside the proper activity to commencement the unlock activity. The activity is however, slightly dissimilar on pre-Honeycomb as well as Honeycomb/ICS devices, so nosotros postulate to banking company fit the Android version, earlier sending it:

try {   if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {     startActivity(new Intent("android.credentials.UNLOCK"));   } else {     startActivity(new Intent("com.android.credentials.UNLOCK"));   } } grab (ActivityNotFoundException e) {     Log.e(TAG, "No UNLOCK activity: " + e.getMessage(), e); } 

Note that the unlock activity is using the transparent theme, so it volition await similar a dialog originating from your ain activity. It is, however, managed yesteryear the system, so your app volition last paused as well as resumed solely after the unlock activity finishes. You postulate to grip this inwards your activity's code (you can't work startActivityForResult() though, since the unlock activity doesn't telephone telephone setResult()). Additionally, if yous don't possess got a device (or credential storage on pre-ICS devices) password laid up, yous volition last prompted to laid one. Control volition last returned to your app solely after yous possess got laid as well as confirmed an unlock password as well as initialized the credential storage.

Now that the keystore is unlocked, nosotros tin get to truly work it. As briefly mentioned above, it uses a local command socket for IPC, as well as the protocol is rather simple: a unmarried missive of the alphabet command, followed yesteryear the length as well as value of whatever parameters (up to two). The protocol is already implemented inwards the android.security.KeyStore class, which is nevertheless hidden from non-system  applications. The argue for non exposing this API given inwards the JavaDoc comment is that 'it assumes that mortal as well as hole-and-corner substitution bytes are available as well as would forestall the work of hardware crypto'. This is a really valid comment: inwards the electrical flow implementation keys are exported as well as imported every bit unencrypted blobs. If the keys were protected yesteryear a hardware device, the API would possess got to render some form of an opaque substitution handle, since the actual substitution textile would non last available, or would solely last exportable if wrapped alongside some other key. If the adjacent Android version introduces hardware cryptography support, the API would possess got to modify dramatically. Having said that, nosotros desire to work the keystore now, so nosotros volition ignore the alert as well as become ahead. Since the KeyStore is hidden nosotros cannot import it directly, but nosotros tin telephone telephone it using reflection. This is slowly plenty to do, but somewhat cumbersome. As the flat doesn't truly possess got whatever dependencies it is easier to re-create it inwards our project, adding a few kid modifications to larn it to compile (see sample code). Once this is done, nosotros tin list, add together as well as larn keys:

KeyStore ks = KeyStore.getInstance(); // larn the names of all keys created yesteryear our app String[] keyNames = ks.saw("");  // shop a symmetric substitution inwards the keystore SecretKey substitution = Crypto.generateKey(); boolean success = ks.put("secretKey1", key.getEncoded()); // banking company fit if functioning succeeded as well as larn mistake code if non if (!success) {    int errorCode = ks.getLastError();    throw novel RuntimeException("Keystore error: " + errorCode);  }  // larn a substitution from the keystore byte[] keyBytes = ks.get("secretKey1"); SecretKey substitution = novel SecretKeySpec(keyBytes, "AES");  // delete a substitution boolean success = ks.delete("secretKey1"); 

As yous tin reckon from the code above, using the credential storage is pretty straightforward. You salve keys yesteryear giving them a call (used every bit percentage of the file call the encrypted blobs are saved into), as well as and so work that call to retrieve or delete them. The UID of the procedure that created the substitution is too a percentage of the file name, as well as so substitution names solely postulate to last unique inside your application. One matter to banking company notation is that KeyStore methods that don't render a value (key name(s) or bytes), render a success flag, so yous postulate to brand certain yous banking company fit it. In illustration of an mistake a to a greater extent than detailed mistake code tin last obtained yesteryear calling getLastError(). All mistake codes are defined inwards the KeyStore class, but yous are most probable to come across PERMISSION_DENIED (if yous get to telephone telephone 1 of the methods reserved for the system user) or KEY_NOT_FOUND (if yous get to access a non-existing key).

Check the sample project for a total app that generates an AES key, encrypts some data, as well as so stores the substitution inwards the arrangement credential storage as well as afterward retrieves it inwards guild to decrypt the data. It generates as well as saves a novel substitution each fourth dimension yous press 'Encrypt' as well as yous tin reckon the stored keys inwards the listing view. Press the 'Reset' push to delete all keys created yesteryear the app. Note that the KeyStore flat used is non compatible alongside the original Donut (Android 1.6) credential storage implementation, but it should piece of work alongside all (public) subsequent versions. Here's how the app's covert looks like. Full code is, every bit usual, on github.


Besides keys yous tin shop whatever sensitive information your app needs such every bit login passwords or tokens. Since decrypting the files on disk requires a substitution derived from the unlock password (or a dedicated password on pre-ICS devices), your secrets cannot last extracted fifty-fifty yesteryear apps alongside root access, or someone alongside physical access to the device (unless they know the password, of course). The principal encryption key, however, is non tied to the device (like in iOS), so it is possible to re-create the encrypted substitution files as well as perform a creature forcefulness onset on a different, to a greater extent than powerful machine(s).

You tin experiment alongside other KeyStore API's, but most of those volition resultant inwards a PERMISSION_DENIED when called from a non-system app. On ICS, at that topographic point is too a world intent (action: com.android.credentials.RESET) that resets the credential storage, so yous could prompt the user to clear it from your app, if necessary. Note that this volition delete all stored information (keys, certificates, etc.), non simply the ones your app created, so work alongside caution.

As a concluding warning, the code presented inwards this ship service does rely on mortal API's as well as OS implementation details, so it mightiness time out alongside the adjacent Android version, or fifty-fifty non piece of work on all electrical flow devices. Keep this inwards heed if yous determine to work it inwards a production app.
0 Komentar untuk "Droidcedas : Storing Application Secrets Inwards Android's Credential Storage"

Back To Top