Android Gated-Authentication Architecture and User Authentication using finger-print has been reviewed in this part.
youtube playlist:
https://www.youtube.com/playlist?list=PLT2xIm2X7W7jyqMXjSpNeRRzgoW_1iJg5
aparat:
https://www.aparat.com/v/LvVtZ
How to do right cryptography in android part 3 / Gated Authentication reviewed
1. Style is like your
fingerprint.
Nobody else has it.
How to do cryptography right in android
Part #3
Arash Ramez
1
2. TOC
• Android Fingerprint Security
• Under the Hood
• How to Implement Fingerprint Authentication
• Communication Channel Validation (TLS)
• Certificate Pinning
• Simple Implementation overview
2
3. Android Gated-Authentication
• Android uses the concept of user-authentication-gated cryptographic keys
that requires the following components:
• Cryptographic key storage and service provider
• Stores cryptographic keys and provides standard crypto routines
• Android supports a hardware-backed Keystore and Keymaster for cryptographic
services
• TEE
• SE (Strongbox)
• User authenticators (through AuthToken)
• Attest to the user's presence and/or successful authentication.
• Android supports Gatekeeper for PIN/pattern/password authentication
and Fingerprint for fingerprint authentication.
• Devices that ship with Android 9 and higher can use BiometricPrompt
• As a single integration point for fingerprint and additional biometrics.
• Authenticated communication channel : Android KeyStore system 3
4. Enrollment
• On first boot of the device after a factory reset, all authenticators are
prepared to receive credential enrollments from the user.
• A user must initially enroll a PIN/pattern/password with Gatekeeper
• This initial enrollment creates a randomly generated, 64-bit User SID (user secure
identifier) that serves as an identifier for the user and as a binding token for the user's
cryptographic material.
• This User SID is cryptographically bound to the user's password;
• successful authentications to Gatekeeper result in AuthTokens that contain the User SID
for that password.
4
5. How does Android save your fingerprints?
• The release of an iPhone without a fingerprint sensor has brought along
some talk about using fingerprints for authentication and how securely
the data is stored.
• It's the same thing as writing something on a post-it note and putting it
in a file cabinet.
• For a file cabinet, you use a lock, and for your phone, you use encryption. For
your fingerprint data, things go one step further: a Trusted Execution
Environment (TEE).
• Not just fingerprint data is stored in the TEE. Things like DRM keys and
manufacturer's bootloader encryption keys also live in the TEE
5
6. TEE OS (Trusty)
• A TEE is a separate and
isolated area in the phone's
hardware.
• The only way you will be
getting in is if the TEE lets you
in, and it never will. Even if the
phone is rooted or the
bootloader unlocked, the TEE
is separate and still intact.
• A very small and efficient
operating system,
appropriately named Trusty
OS, runs on the TEE hardware
and kernel drivers allow it to
communicate with the system.
6
Trusty overview diagram.
7. Enrollment Flow
• When you register a fingerprint on your Android phone, the sensor grabs
the data from the scan.
• Trusty OS analyzes this data inside the TEE, then creates two things: a set of
validation data and an encrypted fingerprint template.
• This appears to be junk data to everything except the TEE who also has the key to
decipher that junk data.
• This encrypted fingerprint template is stored in an encrypted container either on the
TEE or on your phone's encrypted storage. (3 Encryption Layer)
• The validation data is stored inside the TEE. When you place your finger
on the scanner to try and do something, the scanner builds a profile of
data.
• Through the Trusty API, the associated application asks the kernel to ask the TEE if it's
right.
• The TEE checks against the stored validation data using its separate processor and
memory, and if enough of the data matches it says yes.
• This pass or fail response is sent back to the kernel as a software token that the API can read
to see the result. 7
8. The basic rules to building fingerprint sensor
in Android Phone
• All fingerprint data analyzation must be performed inside the TEE
• All the data associated with a fingerprint must be stored in the TEE or in trusted
memory (memory that the main CPU can't even see)
• Fingerprint profile data must be self-encrypted even if stored in encrypted phone
storage
• Removing a user account must also securely wipe any data associated with that
user's fingerprints
• Where fingerprint profiles are stored must not be visible to any application,
process, or user including the root user
• Fingerprint data of any kind must not be backed up to any other source, including
the cloud or your computer or any application
• Fingerprint authentication must be used by the process that requested it (no
sharing of any fingerprint data, even just the yes or no answer to see if it was
correct)
8
9. Enrollment (cont.)
• A user who wants to change a credential must present an existing
credential.
• If an existing credential is verified successfully, the User SID associated with
the existing credential is transferred to the new credential, enabling the user
to keep accessing keys after changing a credential.
• If a user does not present an existing credential, the new credential is
enrolled with a fully random User SID. The user can access the device, but
keys created under the old User SID are permanently lost. This is known as
an untrusted enroll.
• Under normal circumstances, the Android framework does not allow an
untrusted enroll, so most users won't ever see this functionality. However,
forcible password resets, either by a device administrator or an attacker, may
cause this to occur.
9
10. Authentication
• After a user has set up a
credential and received a User
SID, they may proceed to start
authentication, which begins
when a user provides a PIN,
pattern, password, or
fingerprint.
• All TEE components share a
secret key which they use to
authenticate each other's
messages.
Authentication flow.
10
11. Authentication Flow
1. A user provides an authentication method and the associated
service makes a request to the the associated daemon.
• For PIN, pattern, or password, the LockSettingsService makes a request to
gatekeeperd.
• Biometrics-based authentication flows depend on the Android version. On
devices running Android 8.x and lower, FingerprintService makes a request to
fingerprintd).
• On devices running Android 9 and higher, BiometricPrompt makes a request
to the appropriate biometric daemon (for example, fingerprintd for
fingerprints or faced for face) using the appropriate BiometricManager class,
such as FingerprintManager or FaceManager.
• Regardless of version, biometric authentication occurs asynchronously after the request
is sent.
11
12. Authentication Flow
2. The daemon sends data to its counterpart, which generates an
AuthToken:
• For PIN/pattern/password authentication, gatekeeperd sends the PIN,
pattern, or password hash to Gatekeeper in the TEE. If authentication in the
TEE is successful, Gatekeeper in the TEE sends an AuthToken containing the
corresponding User SID (signed with the AuthToken HMAC key) to its
counterpart in the Android OS.
• For fingerprint authentication, fingerprintd listens for fingerprint events and
sends the data to Fingerprint in the TEE. If authentication in the TEE is
successful, Fingerprint in the TEE sends an AuthToken (signed with the
AuthToken HMAC key) to its counterpart in the Android OS.
• For other biometric authentication, the appropriate biometric daemon listens
for the biometric event and sends it to the appropriate biometric TEE
component.
12
13. Authentication Flow (cont.)
3. The daemon receives a signed AuthToken and passes it to the
keystore service via an extension to the keystore service's Binder
interface.
• gatekeeperd also notifies the keystore service when the device is re-locked
and when the device password changes.
4. The keystore service passes the AuthTokens to Keymaster and
verifies them using the key shared with the Gatekeeper and supported
biometric TEE component.
• Keymaster trusts the timestamp in the token as the last authentication time
and bases a key release decision (to allow an app to use the key) on the
timestamp.
• Note: AuthTokens are invalidated when a device reboots.
13
14. AuthToken format
• the AuthToken format
is described in
hw_auth_token.h.
The format is a simple
serialization protocol
with fixed size fields:
14
15. Device boot flow
• On every boot of a device, the AuthToken HMAC key must be
generated and shared with all TEE components (Gatekeeper,
Keymaster, and supported biometrics trustlets)
• Thus, for added protection against replay attacks, the HMAC key must be
randomly generated every time the device reboots.
• The protocol for sharing this HMAC key with all components is a platform-
dependent implementation feature. The key must never be made available
outside the TEE.
• If a TEE OS lacks an internal inter-process communication (IPC) mechanism and needs to
transfer the data through the untrusted OS, the transfer must be done via a secure key
exchange protocol.
15
16. Trusty TEE
• Trusty uses an internal
IPC system to
communicate directly
between Keymaster and
Gatekeeper or the
appropriate biometric
trustlet.
• The HMAC key is kept
solely in Keymaster;
Fingerprint and
Gatekeeper request the
key from Keymaster for
each use and do not
persist or cache the
value.
16
ARM TrustZone TEE block diagram.
17. Fingerprint HAL
• Android uses the Fingerprint
Hardware Abstraction Layer
(HAL) to connect to a vendor-
specific library and fingerprint
hardware, e.g. a fingerprint
sensor.
• To implement the Fingerprint
HAL, you must implement the
major functions of
/hardware/libhardware/include/
hardware/fingerprint.h in a
vendor-specific library.
17
High-level data flow for fingerprint authentication.
18. Fingerprint matching
• The fingerprint sensor of a device is generally idle.
• In response to a call to the authenticate or enroll function, the fingerprint sensor
listens for a touch (the screen might also wake when a user touches the fingerprint
sensor).
• The high-level flow of fingerprint matching includes the following steps:
1. User places a finger on the fingerprint sensor.
2. The vendor-specific library determines if there is a fingerprint match in the current
set of enrolled fingerprint templates.
3. Matching results are passed to the Fingerprint HAL, which notifies fingerprintd (the
Fingerprint daemon) of a fingerprint authentication (or non-authentication).
• Note: The more fingerprint templates stored on a device, the more time
required for fingerprint matching.
18
19. Fingerprint HAL functions
• The Fingerprint HAL contains the following major functions in
/hardware/libhardware/include/hardware/fingerprint.h:
• Enroll
• pre_enroll
• get_authenticator_id
• Cancel
• Enumerate
• Remove
• set_active_group
• Authenticate
• set_notify
19
20. Gatekeeper
• The Gatekeeper subsystem performs device pattern/password
authentication in a Trusted Execution Environment (TEE). Gatekeeper
enrolls and verifies passwords via an HMAC with a hardware-backed secret
key.
• Additionally, Gatekeeper throttles consecutive failed verification attempts and must
refuse to service requests based on a given timeout and a given number of
consecutive failed attempts.
• Gatekeeper involves three main components:
• gatekeeperd (Gatekeeper daemon). A C++ binder service containing platform-
independent logic and corresponding to the GateKeeperService Java interface.
• Gatekeeper Hardware Abstraction Layer (HAL). The HAL interface in
hardware/libhardware/include/hardware/gatekeeper.h, and the implementing
module.
• Gatekeeper (TEE). The TEE counterpart of gatekeeperd. A TEE-based implementation
of Gatekeeper. 20
23. Traditional Steps for Fingerprint Authentication
• 1. Request fingerprint authentication permission within the project
Manifest file.
• 2. Verify that the lock screen of the device on which the app is running is
protected by a PIN, pattern or password (fingerprints can only be
registered on devices on which the lock screen has been secured).
• 3. Verify that at least one fingerprint has been registered on the device.
• 4. Create an instance of the FingerprintManager class.
• 5. Use a Keystore instance to gain access to the Android Keystore container.
This is a storage area used for the secure storage of cryptographic keys on
Android devices.
23
24. Traditional Steps for Fingerprint
Authentication (cont.)
• 6. Generate an encryption key using the KeyGenerator class and store
it in the Keystore container.
• 7. Initialize an instance of the Cipher class using the key generated in
step 5.
• 8. Use the Cipher instance to create a CryptoObject and assign it to
the FingerprintManager instance created in step 4.
• 9. Call the authenticate method of the FingerprintManager instance.
• 10. Implement methods to handle the callbacks triggered by the
authentication process. Provide access to the protected content or
functionality on completion of a successful authentication.
24
25. Fingerprint Authentication
• First Review popular code
• https://www.androidauthority.com/how-to-add-fingerprint-authentication-
to-your-android-app-747304/
• https://proandroiddev.com/5-steps-to-implement-biometric-authentication-
in-android-dbeb825aeee8
25
26. Required Permission
• Adding the Fingerprint Permission to the Manifest File
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.an.biometric">
<!-- Step 1: Add the following permission to the app -->
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<!-- Step 2: This permission is depreciated in Android P -->
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
</manifest>
26
27. Accessing the Keyguard and Fingerprint
Manager Services
• Fingerprint authentication
makes use of two system
services in the form of the
KeyguardManager and the
FingerprintManager. Edit the
onCreate method located in
the
FingerprintDemoActivity.java
file to obtain references to
these two services as follows:
27
28. Checking the Security
Settings
• Earlier steps were taken to
configure the lock screen and
register fingerprints on the
device or emulator on which the
app is going to be tested. It is
important, however, to include
defensive code in the app to
make sure that these
requirements have been met
before attempting to seek
fingerprint authentication.
28
29. Accessing the Android Keystore and
KeyGenerator
• Part of the fingerprint
authentication process
involves the generation
of an encryption key
which is then stored
securely on the device
using the Android
Keystore system. Before
the key can be
generated and stored,
the app must first gain
access to the Keystore
29
30. Generating the Key
• Now that we have a reference
to the Android Keystore
container and a KeyGenerator
instance, the next step is to
generate the key that will be
used to create a cipher for the
encryption process. Remaining
within the
FingerprintDemoActivity.java
file, add this new code as
follows:
30
31. Initializing the Cipher
• Now that the key has been
generated the next step is to
initialize the cipher that will
be used to create the
encrypted
FingerprintManager.CryptoO
bject instance. This
CryptoObject will, in turn, be
used during the fingerprint
authentication process.
31
32. Creating the CryptoObject Instance
• Remaining within the
FingerprintDemoActivi
ty.java file, modify the
onCreate method to
call the two newly
created methods and
generate the
CryptoObject as
follows:
•
32
33. Implementing the Fingerprint Authentication
Handler Class
• The actual authentication is
triggered via a call to the
authenticate method of the
FingerprintManager instance.
• This method call, however, will
trigger one of a number of callback
events depending on the success or
failure of the authentication. Both
the authenticate method call and
the callback handler methods need
to be implemented in a class that
extends the
FingerprintManager.Authentication
Callback class
33
35. What’s wrong about this approach?
• Security Feature or Usability Feature?
• Security Feature != Secure Feature
• Complete mediation principle
• Authentication is an server-side security control not client-side
• How Local Authentication would facilitates user authentication
35
37. Complete Mediation Principle
• Verify all pages and resources by default require authentication
except those specifically intended to be public (Principle of complete
mediation).
37
38. Local Authentication on Android
• During local authentication, an app
authenticates the user against credentials
stored locally on the device.
• In other words, the user "unlocks" the app or
some inner layer of functionality by providing a
valid PIN, password, or fingerprint, verified by
referencing local data.
• Generally, this process is invoked for reasons such
providing a user convenience for resuming an
existing session with the remote service or as a
means of step-up authentication to protect some
critical function.
38
39. Local Authentication on Android (cont.)
• It is important to reassure that authentication happens at least on a
cryptographic primitive (e.g.: an authentication step which results in
unlocking a key).
• Next, it is recommended that the authentication is verified at a
remote endpoint.
• In Android, there are two mechanisms supported by the Android
Runtime for local authentication: the Confirm Credential flow and
the Biometric Authentication flow.
39
40. Biometric Authentication
• Access to the fingerprint hardware is provided through
the FingerprintManager class.
• An app can request fingerprint authentication by instantiating a
FingerprintManager object and calling its authenticate() method. The caller
registers callback methods to handle possible outcomes of the authentication
process (i.e. success, failure, or error).
• Note that this method doesn't constitute strong proof that
fingerprint authentication has actually been performed –
• for example, the authentication step could be patched out by an attacker, or
the "success" callback could be called using instrumentation.
40
41. Biometric Authentication
• Better security is achieved by using the fingerprint API in
conjunction with the Android KeyGenerator class.
• With this method, a symmetric key is stored in the KeyStore and
"unlocked" with the user's fingerprint.
• For example, to enable user access to a remote service, an AES key is created
which encrypts the user PIN or authentication token.
• The encrypted authentication credentials can then be saved directly to
regular storage on the the device (e.g. SharedPreferences)
41
42. Better Implementation
• Two Step : Encrypt / Decrypt Credentials
• Encryption:
• User gives helper the desired non-encrypted password.
• User is required to provide fingerprint.
• Once authenticated, the helper obtains a key from the Keystore and encrypts
the password using a Cipher.
• Password and IV salt (IV is recreated for every encryption and is not reused)
are saved to shared preferences to be used later in the decryption process.
• Decryption
• User requests to decrypt the password.
• User is required to provide fingerprint.
• The helper builds a Cipher using the IV and once user is authenticated, the
Keystore obtains a key from the KeyStore and deciphers the password.
43. • The permission must be requested in the Android Manifest:
• Fingerprint hardware must be available:
43
44. • The user must have a protected lock screen:
• At least one finger should be registered:
44
45. • The application should have permission to ask for a user fingerprint:
• On certain systems, it is possible to enforce the policy for biometric
authentication through hardware as well. This is checked by:
45
46. Fingerprint Authentication using a Symmetric
Key
• Fingerprint authentication may be implemented by creating a new
AES key using the KeyGenerator class by adding
setUserAuthenticationRequired(true) in
KeyGenParameterSpec.Builder
46
47. • To perform encryption or decryption with the protected key, create a
Cipher object and initialize it with the key alias.
• Keep in mind, a new key cannot be used immediately - it has to be
authenticated through the FingerprintManager first. This involves
wrapping the Cipher object into FingerprintManager.CryptoObject
which is passed to FingerprintManager.authenticate() before it will be
recognized.
47
48. • When the authentication succeeds, the callback method
onAuthenticationSucceeded(FingerprintManager.AuthenticationResul
t result) is called at which point, the authenticated CryptoObject can
be retrieved from the result.
48
49. Using Asymmetric Key
• An even more secure option is using asymmetric cryptography.
• Here, the mobile app creates an asymmetric key pair in the KeyStore
and enrolls the public key on the server backend. Later transactions
are then signed with the private key and verified by the server using
the public key. The advantage of this is that transactions can be
signed using KeyStore APIs without ever extracting the private key
from the KeyStore. Consequently, it is impossible for attackers to
obtain the key from memory dumps or by using instrumentation.
49
Biometric API. For devices that launcher with Android 8.1 and lower, FingerprintManager interacts directly with an app in an app process. Each app has an instance of FingerprintManager, a wrapper that communicates with FingerprintService.Devices that ship with Android 9 and higher, should use the BiometricPrompt API instead of FingerprintManager.
FingerprintService. Singleton service that operates in the system process, which handles communication withfingerprintd.
fingerprintd. C/C++ implementation of the binder interface from FingerprintService. The fingerprintddaemon operates in its own process and wraps the Fingerprint HAL vendor-specific library.
Fingerprint HAL vendor-specific library. Hardware vendor's implementation of the Fingerprint HAL. The vendor-specific library communicates with the device-specific hardware.
Keystore API and Keymaster. Components that provide hardware-backed cryptography for secure key storage in a Trusted Execution Environment (TEE).
This flow assumes a fingerprint has already been enrolled on the device, i.e. the vendor-specific library has enrolled a template for the fingerprint (for details, see Authentication).
enroll. Switches the HAL state machine to start the collection and storage of a fingerprint template. When enrollment is complete, or after a timeout, the HAL state machine returns to the idle state.
pre_enroll. Generates a unique token to indicate the start of a fingerprint enrollment. Provides a token to the enroll function to ensure there was prior authentication, e.g. using a password. To prevent tampering, the token is wrapped (e.g. HMAC'd) after the device credential is confirmed. The token must be checked during enrollment to verify the token is still valid.
get_authenticator_id. Returns a token associated with the current fingerprint set.
cancel. Cancels pending enroll or authenticate operations. The HAL state machine is returned to the idle state.
enumerate. Synchronous call for enumerating all known fingerprint templates.
remove. Deletes a fingerprint template.
set_active_group. Restricts a HAL operation to a set of fingerprints that belong to a specified group, identified by a group identifier (GID).
authenticate. Authenticates a fingerprint-related operation (identified by an operation ID).
set_notify. Registers a user function that receives notifications from the HAL. If the HAL state machine is in a busy state, the function is blocked until the HAL leaves the busy state.
Gatekeeper requires implementation of the Gatekeeper HAL (specifically the functions inhardware/libhardware/include/hardware/gatekeeper.h) and the TEE-specific Gatekeeper component (based in part on the system/gatekeeper/include/gatekeeper/gatekeeper.h header file that includes pure virtual functions for creating/accessing keys and computing signatures).
The LockSettingsService makes a request (via Binder) that reaches the gatekeeperd daemon in the Android OS. The gatekeeperd daemon then makes a request that reaches its counterpart (Gatekeeper) in the TEE:
These steps will be performed within the onCreate method residing in the FingerprintDemoActivity.java file, making use of the Keyguard and Fingerprint manager services. Note that code has also been added to verify that the USE_FINGERPRINT permission has been configured for the app:
A reference to the Keystore is obtained by calling the getInstance method of the Keystore class and passing through the identifier of the standard Android keystore container (“AndroidKeyStore”). The next step in the tutorial will be to generate a key using the KeyGenerator service. Before generating this key, code needs to be added to obtain a reference to an instance of the KeyGenerator, passing through as arguments the type of key to be generated and the name of the Keystore container into which the key is to be saved:
Next, the keystore container is loaded and the KeyGenerator initialized. This initialization process makes use of the KeyGenParameterSpec.Builder class to specify the type of key being generated. This includes referencing the key name, configuring the key such that it can be used for both encryption and decryption, and setting various encryption parameters. The setUserAuthenticationRequired method call configures the key such that the user is required to authorize every use of the key with a fingerprint authentication. Once the KeyGenerator has been configured, it is then used to generate the key via a call to the generateKey method of the instance.
Cipher configuration involves obtaining a Cipher instance and initializing it with the key stored in the Keystore container. Add a new method named cipherInit to the FingerprintDemoActivity.java file to perform these tasks:
The getInstance method of the Cipher class is called to obtain a Cipher instance which is subsequently configured with the properties required for fingerprint authentication. The previously generated key is then extracted from the Keystore container and used to initialize the Cipher instance. Errors are handled accordingly and a true or false result returned based on the success or otherwise of the cipher initialization process.
Work is now complete on both the generateKey and cipherInit methods. The next step is to modify the onCreate method to call these methods and, in the event of a successful cipher initialization, create a CryptoObject instance.