BiometricPrompt API ● Known as FingerprintDialog API in early versions of P Preview (as at the time of submission of this talk) ● Provide consistent and easy API for developers
BiometricPrompt API ● Known as FingerprintDialog API in early versions of P Preview (as at the time of submission of this talk) ● Provide consistent and easy API for developers ● Provide consistent system UI that is sensor-agnostic
Symmetric vs Asymmetric Keystore Symmetric: aka “secret key” - same key for encryption and decryption Asymmetric: aka “public key” - different keys for encryption and decryption https://www.cs.utexas.edu/users/byoung/cs361/lecture44.pdf
Android Keystore Hardware backed keystore that lets you store cryptographic keys in a container and makes it more difficult to extract from the device.
Check other criteria val fingerprintManager = getSystemService(FingerprintManager::class.java) val keyguardManager = getSystemService(KeyguardManager::class.java) // Show error - can't proceed without sensor if (!fingerprintManager.isHardwareDetected) {...}
Check other criteria val fingerprintManager = getSystemService(FingerprintManager::class.java) val keyguardManager = getSystemService(KeyguardManager::class.java) // Show error - can't proceed without sensor if (!fingerprintManager.isHardwareDetected) {...} // Show error - can't proceed without fingerprint if (!fingerprintManager.hasEnrolledFingerprints()) {...}
Check other criteria val fingerprintManager = getSystemService(FingerprintManager::class.java) val keyguardManager = getSystemService(KeyguardManager::class.java) // Show error - can't proceed without sensor if (!fingerprintManager.isHardwareDetected) {...} // Show error - can't proceed without fingerprint if (!fingerprintManager.hasEnrolledFingerprints()) {...}
Check other criteria val fingerprintManager = getSystemService(FingerprintManager::class.java) val keyguardManager = getSystemService(KeyguardManager::class.java) // Show error - can't proceed without sensor if (!fingerprintManager.isHardwareDetected) {...} // Show error - can't proceed without fingerprint if (!fingerprintManager.hasEnrolledFingerprints()) {...} // Proceed with auth
Check other criteria val fingerprintManager = getSystemService(FingerprintManager::class.java) val keyguardManager = getSystemService(KeyguardManager::class.java) // Show error - can't proceed without sensor if (!fingerprintManager.isHardwareDetected) {...} // Show error - can't proceed without fingerprint if (!fingerprintManager.hasEnrolledFingerprints()) {...} // Proceed with auth Deprecated
Check other criteria val fingerprintManager = getSystemService(FingerprintManager::class.java) val keyguardManager = getSystemService(KeyguardManager::class.java) // Show error - can't proceed without sensor if (!fingerprintManager.isHardwareDetected) {...} // Show error - can't proceed without fingerprint if (!fingerprintManager.hasEnrolledFingerprints()) {...} // Proceed with auth New API offers callbacks to handle errors and unsatisfied criteria
Create key store from the AndroidKeyStore // Create Keystore try { keyStore = KeyStore.getInstance("AndroidKeyStore") } catch (e: KeyStoreException) { throw RuntimeException("Failed to get an instance of KeyStore", e) } 2. Create & initialize a cipher
Create KeyGenerator that will be used to create the symmetric key // Create Keystore try { keyStore = KeyStore.getInstance("AndroidKeyStore") } catch (e: KeyStoreException) { throw RuntimeException("Failed to get an instance of KeyStore", e) } // Create KeyGenerator (this will be used to create the key) try { keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM_AES, "AndroidKeyStore") } catch (e: Exception) { when (e) { is NoSuchAlgorithmException, is NoSuchProviderException -> throw RuntimeException(...) else -> throw e } 2. Create & initialize a cipher
Use KeyGenerator to generate keys try { keyStore.load(null) val keyProperties = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT val builder = KeyGenParameterSpec.Builder(“default_key”, keyProperties) .setBlockModes(BLOCK_MODE_CBC) .setUserAuthenticationRequired(true) .setEncryptionPaddings(ENCRYPTION_PADDING_PKCS7) .setInvalidatedByBiometricEnrollment(true) // generate keys keyGenerator.init(builder.build()) keyGenerator.generateKey() } catch (e: Exception) { // handle exceptions } Key is authorized to be used only when user has been authenticated (e.g unlocked phone)
Key is invalidated when a new fingerprint is added Use KeyGenerator to generate keys try { keyStore.load(null) val keyProperties = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT val builder = KeyGenParameterSpec.Builder(“default_key”, keyProperties) .setBlockModes(BLOCK_MODE_CBC) .setUserAuthenticationRequired(true) .setEncryptionPaddings(ENCRYPTION_PADDING_PKCS7) .setInvalidatedByBiometricEnrollment(true) // generate keys keyGenerator.init(builder.build()) keyGenerator.generateKey() } catch (e: Exception) { // handle exceptions }
Create a cipher // Create a cipher val cipher : Cipher try { val cipherString = "$KEY_ALGORITHM_AES/$BLOCK_MODE_CBC/$ENCRYPTION_PADDING_PKCS7" cipher = Cipher.getInstance(cipherString) } catch (e: Exception) { when (e) { is NoSuchAlgorithmException, is NoSuchPaddingException -> throw RuntimeException("Failed to get an instance of Cipher", e) else -> throw e } }
Initialize the cipher fun initCipher(cipher: Cipher): Boolean { try { keyStore.load(null) val secretKey = keyStore.getKey("default_key", null) as SecretKey // init cipher.init(Cipher.ENCRYPT_MODE, secretKey) return true } catch (e: Exception) { when (e) { is KeyPermanentlyInvalidatedException -> return false ... else -> throw e } } } Unrecoverably invalidated due to - change in security settings of the phone, or since we configured setInvalidatedByBiometricEnrollment to enrollment of new fingerprint
val cancellationSignal = new CancellationSignal(); val cryptoObject = FingerprintManager.CryptoObject(cipher) // Warm up the sensor and start listening for authentication val manager = getSystemService(FingerprintManager::class.java) manager.authenticate(cryptoObject, cancellationSignal, 0, callback, null); 3. Listen for fingerprint auth events Authenticating with the old FingerprintManager
val cancellationSignal = new CancellationSignal(); val cryptoObject = FingerprintManager.CryptoObject(cipher) // Warm up the sensor and start listening for authentication val manager = getSystemService(FingerprintManager::class.java) manager.authenticate(cryptoObject, cancellationSignal, 0, callback, null); 3. Listen for fingerprint auth events Authenticating with the old FingerprintManager Deprecated
Last words... ● Provide alternative ways to authenticate (password, OTP, and other ways) ● Subtle enrollment - there should be a place in your settings where users can enroll to use fingerprint authentication in your app
Last words... ● Provide alternative ways to authenticate (password, OTP, and other ways) ● Subtle enrollment - there should be a place in your settings where users can enroll to use fingerprint authentication in your app ● Provide as much info as possible to your users to help them
Last words... ● Provide alternative ways to authenticate (password, OTP, and other ways) ● Subtle enrollment - there should be a place in your settings where users can enroll to use fingerprint authentication in your app ● Provide as much info as possible to your users to help them ● Ensure good API practices with signed requests
Last words... ● Provide alternative ways to authenticate (password, OTP, and other ways) ● Subtle enrollment - there should be a place in your settings where users can enroll to use fingerprint authentication in your app ● Provide as much info as possible to your users to help them ● Ensure good API practices with signed requests ● The APIs may not be final yet
Last words... ● Provide alternative ways to authenticate (password, OTP, and other ways) ● Subtle enrollment - there should be a place in your settings where users can enroll to use fingerprint authentication in your app ● Provide as much info as possible to your users to help them ● Ensure good API practices with signed requests ● The APIs may not be final yet ● No Compat APIs yet