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
- Created in hardware and stored in the hardware-backed keystore
- 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
- IV stored on disk unencrypted
- The app prompts user to choose a password (lots of hints to make it a good one)
- Salt generated and stored on disk unencrypted
SHA256(password + salt), where
+is byte-array concatenation, stored on disk unencrypted
Each time the app starts, unless the key changes:
- Fingerprint requested from user to unlock hardware-backed keystore
- AES key from keystore used to decipher the data file and load plaintext data to memory (key does not enter system memory)
- Plaintext data deserialized and used
- Another cipher instance initialized while the keystore is open to be used later
- Keystore closed
When saving data:
- Data serialized
- Data enciphered using cipher from step 4. above.
- Encrypted data saved to disk.
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?