Android Fingerprint API
A crash course in fingerprint authentication
What is the Fingerprint API?
Congrationations: You are part of the
<0.7 %
It will get better
- Sony
- OnePlus
- Samsung
- and more Marshmallow updates
It might get better
- Sony
- OnePlus
- Samsung
- and more Marshmallow updates
Why is fingerprint better than a password?
"Nobody wants to enter a password!"
Nobody wants to open a lock with a key, but wants the door to open once they are close
Passwords suck UX wise
- Forget password
- Enter password
- I just want to be authenticated
Your users don't use your app every day
I have to interact with the display
I want stuff to work automatically
Not talking about security
With Code!!
... and hopefully some nice UI
Prequisites
targetSdkVersion 23
USE_FINGERPRINT permission
Device or emulator with fingerprint sensor
Fingerprint Classes
- FingerprintManager
- CancellationSignal
- AuthenticationCallback
- CryptoObject
FingerprintManager
And forget FingerprintManager again -> FingerprintManagerCompat
FingerprintManagerCompat
Now we can actually use this with pre Marshmallow devices
Not use, but it won't crash
FingerprintManagerCompat
return FingerprintManagerCompat.from(context);
FingerprintManagerCompat
warms up the fingerprint sensor so it's ready to detect fingers but wait!!
FingerprintManagerCompat
- #isHardwareDetected
- #hasEnrolledFingerprints
check if fingerprint authentication is possible
#authenticate(...)
- CryptoObject
- flags
- CancellationSignal
- AuthenticationCallback
- Handler
now we're sure fingerprint authentication will work. call authenticate to allow user to use the sensor.
#authenticate(...)
- (CryptoObject)
- flags
- CancellationSignal
- AuthenticationCallback
- Handler
CryptoObject - Used for crypto operations related to the authentication
More later
Optional! Can be null
#authenticate(...)
- (CryptoObject)
- (flags)
- CancellationSignal
- AuthenticationCallback
- Handler
"Optional flags, should be 0" - documentation
#authenticate(...)
- (CryptoObject)
- (flags)
- CancellationSignal
- AuthenticationCallback
- (Handler)
Handler where callbacks should run
Optional, can be null
#authenticate(...)
- (CryptoObject)
- (flags)
- CancellationSignal
- AuthenticationCallback
- (Handler)
Create and store this somewhere
Cancel operation when not needed anymore
Also has callbacks if you want to execute stuff after operation cancelled
#authenticate(...)
- (CryptoObject)
- (flags)
- CancellationSignal
- AuthenticationCallback
- (Handler)
This is the big one
Callback for results of the authentication
onAuthentication...
- Succeeded
- Error
- Failed
- Help
onAuthenticationError
- Fingerprint detection not possible
- Operation cancelled
Error is bad, and it will cancel the operation
Maybe the sensor is broken,
fell out or is just sad today and doesn't want to work
Also if operation running too long or too many wrong attempts
onAuthenticationFailed
- Fingerprint detected but not authenticated
Will not cancel the operation, you can try again
Wrong finger, wrong person
onAuthenticationHelp
- Recoverable error
- Help string provided
Operation still active
Moved finger too fast, too little.
Dirt
Unclear image
Just try again, it will work next time
onAuthenticationSucceeded
- Fingerprint was detected and authenticated
- Access to CryptoObject
yay!
We have our user (maybe)
Any finger registered in the device was found
But what about my UI?
Just build it!
No standard UI exists
Typically a dialog
Must not be a dialog
Use this icon in your UI
"You must implement the user interface for the fingerprint authentication flow on your app, and use the standard Android fingerprint icon in your UI."
d.android.com
Though you can tint the icon background
UX
Let the user chose to set up fingerprint
Always provide a fallback
Show the user success and error states!
Setup during purchase flow, maybe app start to lock the app
Once setup, let the user go back to password!
CryptoObject
now you're encrypting with fingerprints
Fingerprint authentication
...replaces some sort of other authentication
You wouldn't just add fingerprint authentication for the sake of it.
User should be present
Maybe you still need your old form of authentication for network calls
Think password, token, pin, something else
Where do you store it?
CryptoObject allows encryption
- Relies on Android KeyStore
- Only accessible by biometric authentication
Encryprion and decryption with Android KeyStore
Biometric authentication if you set it up correctly
CryptoObject
Focus on Cipher
CryptoObject
- Set up Cipher
- Set up Key in KeyStore
- Init Cipher with Key
- Create CryptoObject with Cipher
4 easy steps we will go through
Set up Cipher
return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7
);
4 easy steps we will go through
Set up Key in KeyStore
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
keyGenerator.init(new KeyGenParameterSpec.Builder(keyName, PURPOSE_ENCRYPT | PURPOSE_DECRYPT)
.setBlockModes(BLOCK_MODE_CBC)
.setEncryptionPaddings(ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.build());
return keyGenerator.generateKey();
Set up Key in KeyStore
KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
keyGenerator.init(new KeyGenParameterSpec.Builder(keyName, PURPOSE_ENCRYPT | PURPOSE_DECRYPT)
.setBlockModes(BLOCK_MODE_CBC)
.setEncryptionPaddings(ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.build());
return keyGenerator.generateKey();
Or load your Key from the KeyStore
Userauthentication required! Means lock screen authentication
Fingerprint required to use this key
Don't just create a new key every time or for decryption
Init your Cipher
cipher.init(Cipher.ENCRYPT_MODE, key);
Encrypt mode with the key we just found
Init your Cipher
cipher.init(Cipher.ENCRYPT_MODE, key);
Encrypt mode with the key we just found
Init your Cipher for decryption
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
Decrypt mode and store the Initialization Vector somewhere
You can retrieve this after the encryption from the Cipher
Init your Cipher for decryption
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
Decrypt mode and store the Initialization Vector somewhere
You can retrieve this after the encryption from the Cipher
Init your Cipher for decryption
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
IV can be stored somewhere.
Do not reuse IV's!
Create CryptoObject with Cipher
CryptoObject cryptoObject = new FingerprintManagerCompat.CryptoObject(cipher);
fingerprintManager.authenticate(cryptoObject, 0, cancellationSignal, callback, null);
Pass this into the .authenticate() call
Nothing is encrypted yet!
And hope for the succeeded callback!
Create CryptoObject with Cipher
CryptoObject cryptoObject = new FingerprintManagerCompat.CryptoObject(cipher);
fingerprintManager.authenticate(cryptoObject, 0, cancellationSignal, callback, null);
Pass this into the .authenticate() call
Nothing is encrypted yet!
And hope for the succeeded callback!
onAuthenticationSucceeded(AuthenticationResult)
Access to the CryptoObject
onAuthenticationSucceeded(AuthenticationResult)
Cipher cipher = authenticationResult.getCryptoObject().getCipher();
byte[] encryptedBytes = cipher.doFinal("1234".getBytes("UTF-8"));
onAuthenticationSucceeded(AuthenticationResult)
Cipher cipher = authenticationResult.getCryptoObject().getCipher();byte[] encryptedBytes = cipher.doFinal("1234".getBytes("UTF-8"));
get access to the cipher
onAuthenticationSucceeded(AuthenticationResult)
Cipher cipher = authenticationResult.getCryptoObject().getCipher();
byte[] encryptedBytes = cipher.doFinal("1234".getBytes("UTF-8"));
Encrypt with the doFinal method
Result is encrypted byte array
Changing the lockscreen
KeyPermanentlyInvalidatedException
All your encryption keys are invalidated
Makes sense, but is annoying
Protects your encrypted data
UX vs. Security
- Fingerprint != your user
- Password will be stronger
- You cannot change your fingerprint
- But fingerprint sensors are so very convenient
Android Fingerprint API
A crash course in fingerprint authentication
Marvin Ramin