GuilhE
GuilhE

Reputation: 11901

Save sensitive data on Android with EncryptedSharedPreferences and Biometric

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"?

Upvotes: 2

Views: 2923

Answers (2)

Alessandro Scarozza
Alessandro Scarozza

Reputation: 4438

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"));
});

Upvotes: 1

Michael
Michael

Reputation: 58507

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.

Upvotes: 2

Related Questions