2

I want to store sensitive information like a login PIN. Today with EncryptedSharedPreferences (ESP) one can argue that's enough. But let's say I want to offer the possibility to use Biometrics. This google sample show us how to use BiometricPrompt.CryptoObject for data encryption and decryption.

But this raises one question:
Should I save the PIN in ESP without adding another layer of security?

If so, the Biometric prompt will act like a faster and convenient way for inserting the PIN. I just have to listen for the onAuthenticationSucceeded ignoring the result: BiometricPrompt.AuthenticationResult and assume the user is logged (or perform a API login with the PIN value saved in ESP). If I save the PIN in ESP but with an extra layer of security provided by the encryption of the CryptographyManager (cryptographyManager.encryptData / cryptographyManager.decryptData) I'll run into trouble when the user inserts the PIN manually, because I'll have no way to encrypt the inserted data and compare with the encrypted stored one. In this scenario I'll not have a Cipher object since there's no BiometricPrompt (let's say I want to offer the possibility for offline login).

Maybe I'm missing a step here, but is it enough to store the PIN in ESP and use only the Biometrics for "handy login"?

Michael
  • 57,169
  • 9
  • 80
  • 125
GuilhE
  • 11,591
  • 16
  • 75
  • 116

2 Answers2

2

The keys that encrypt your encrypted shared preferences are in turn encrypted with a master key. MasterKeys.getOrCreate takes a KeyGenParameterSpec as its input.

Instead of just using the predefined MasterKeys.AES256_GCM_SPEC you can build your own KeyGenParameterSpec with the settings you want, e.g. specifying that user authentication should be required.

See the points under "For use cases requiring additional security, complete the following steps" here.

Michael
  • 57,169
  • 9
  • 80
  • 125
  • Thanks for your comment, it's really helpful regarding "Require user authentication for key use". Maybe I've explained myself poorly. The PIN that I mention, is not the system PIN, it's an Application PIN (custom implementation). The user may choose to always insert by hand or use Biometrics to be faster (of course when he's creating the PIN he has to input it manually first and twice for validation). My doubt in this situation is when the user inserts a PIN manually without using systems Biometric. From this point on, Biometric will be just a "faster way" to insert the PIN right? – GuilhE Mar 04 '20 at 10:17
  • continuation: Even if he accepts the use of Biometrics (upon creating the app PIN), if latter he decides to login via manual PIN I've to be capable to compare the input with the value stored in `EncryptSharedPreferences`. And for that I cannot encrypt the PIN with the `BiometricPrompt`results right? – GuilhE Mar 04 '20 at 10:25
  • 1
    If you're still talking about `EncryptSharedPreferences`, then it does not work together with `BiometricPrompt` as far as I know. As the steps in the last link I posted explains, what you do is launch a system activity that will ask the user to confirm their credentials (using e.g. some kind of biometrics or the device PIN). If this succeeds it temporarily unlocks the masterkey which is needed to access your encrypted sharedpreferences. – Michael Mar 04 '20 at 10:30
  • Exactly. But how does Revolut, for example, handle this situation? The PIN is not from the system, it's an Custom UI widget from the app itself. You can login manually or by Biometric. I'm facing the same use-case. In this scenario I'm saving the PIN in `EncryptSharedPreferences` as is. Latter, if the user uses Biometrics to login, this process will only validate the user authenticity instead of unlocking the masterkey. In use-cases like this, the Biometric will just be used for "fast login" since the only way to work together is by system PIN/Biometric, etc.., no app custom PINs, right? – GuilhE Mar 04 '20 at 11:22
  • Why do you need to store the actual PIN though? Can't you store some derivate of the PIN instead? (see e.g. https://owasp.org/www-project-cheat-sheets/cheatsheets/Password_Storage_Cheat_Sheet) – Michael Mar 04 '20 at 11:32
1

i made a library to do exactly this:

This library use livedata to merge androidx.security with androidx.biometric using setUserAuthenticationRequired

https://github.com/xanscale/LocalhostToolkit/tree/master/security

You can just use this inside fragment or activity

BiometricEncryptedSharedPreferences.create(
        this,
        "secret_shared_prefs",
        1,
        new BiometricPrompt.PromptInfo.Builder().setTitle(getString(R.string.app_name)).setDeviceCredentialAllowed(true).build()
).observe(this, it -> {
    it.edit().putString("secretValue", "IT works!").apply();
    System.out.println(it.getString("secretValue", "It didn't work"));
});
Alessandro Scarozza
  • 4,273
  • 6
  • 31
  • 39
  • Share the link so we can have a look :) – GuilhE May 06 '20 at 22:31
  • @GuilhE any feedback? – Alessandro Scarozza May 12 '20 at 15:17
  • Hi Xan, a quick look through your code and your lib does not solve the problems here stated, maybe you misunderstood the point. Never the less, it's a good helper class to setup biometric prompt with LiveData – GuilhE May 12 '20 at 15:26
  • @GuilhE you asked for another layer of security ? this library change ESP adding "UserAuthenticationRequired". in that way to access the encryption keys user must me authenticated throught biometric, – Alessandro Scarozza May 12 '20 at 16:15
  • Look closer, including all the comments with Michael, I'm talking about an onboarding with custom authentication and biometricPrompt. They can't work together, either we choose system biometric or we have to create our custom PIN and then use biometricPrompt only to validate authenticity. Your lib looks good bu if for some reason I want to type PIN I have to use the system PIN/Pattern right? But what If we want some custom UI PIN authentication, like Revolut. We can't use the biometric to change keys etc, only to validate that biometric check "its mine". – GuilhE May 12 '20 at 18:16