I'm writing an Android app which will need to store some data for the user as a byte array of unknown length. The data must be encrypted. I have gone down the path of the hardware-backed keystore and this is where I am:

At first start after installation:

  • The app has an AES-128 key and IV for CBC generated
    1. Created in hardware and stored in the hardware-backed keystore
    2. Flags set:
      • only reveal the key to this app and only do so when the user passes fingerprint authentication
      • delete the key and generate another from the same parameters if another fingerprint is enrolled
    3. IV stored on disk unencrypted
  • The app prompts user to choose a password (lots of hints to make it a good one)
    1. Salt generated and stored on disk unencrypted
    2. SHA256(password + salt), where + is byte-array concatenation, stored on disk unencrypted

Each time the app starts, unless the key changes:

  1. Fingerprint requested from user to unlock hardware-backed keystore
  2. AES key from keystore used to decipher the data file and load plaintext data to memory (key does not enter system memory)
  3. Plaintext data deserialized and used
  4. Another cipher instance initialized while the keystore is open to be used later
  5. Keystore closed

When saving data:

  1. Data serialized
  2. Data enciphered using cipher from step 4. above.
  3. Encrypted data saved to disk.

Note the

unless the key changes

On regular start. In this case, the key has been invalidated by enrollment of further fingerprints making the encrypted data file useless. From here, the user is prompted for their password which is checked. At this point my app will know that the user is or is not authenticated to use the AES key in the keystore, but the keystore is not convinced since the app told it not to dispense the key unless the user authenticated with biometrics.

Here are two options I have considered:

  • Store another copy of the data file encrypted with AES-128, using as the key SHA256(password + salt) (mod 2^128) or some other 128-bit transformation of the hash
  • Disable the below flag when creating the key

    delete the key and generate another from the same parameters if another fingerprint is enrolled

... and here are the reasons for which I do not like those above:

  • But then the level of security is reduced from about 128 bits to that of whatever password the user thinks up (probably much less than 128 bits)
  • Goes against my instincts because it feels like cutting corners in a security context.

What should I do here - do I just have to face the fact that either enrollment does not invalidate the key or the security on the file is only as strong as the user's password?

  • $\begingroup$ There are a few issues with your scheme. But before I can answer, I need to know whether it's acceptable to just give the user a (strong, short) password which he should write down and store away in case the app fails to authenticate? $\endgroup$ – SEJPM Nov 24 '16 at 10:33
  • $\begingroup$ @SEJPM I appreciate the suggestion. That's not out of the question, but it would be preferable to have the user generate it themselves and have the app insist on rather strict rules for minimum security EG length > 30, upper, lower, digits, and symbols all required $\endgroup$ – Scruffy Nov 24 '16 at 10:59
  • $\begingroup$ Asking the user to pick a 30+ character password with all those requirements would probably result in passwords written down somewhere. Allowing a passphrase of that length (i.e., no digit/symbol/upper/lower requirements) would be a lot nicer to your users. $\endgroup$ – Justin Bailey Nov 29 '16 at 18:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.