KeyGenParameterSpec.Builder.setUserAuthenticationRequired(true) signifies that a Key in the Android Key Store is only authorized when:
The user is authenticated using a subset of their secure lock screen
credentials (pattern/PIN/password, fingerprint).
If enabled, UserNotAuthenticatedException will be thrown any time a Key is generated or the KeyStore is accessed when the user is not authenticated.
Is there an API call to reliably check that the user is indeed authenticated prior to interacting with the KeyStore?...rather than relying solely on catching the exception after the fact.
Android provides the ability to check this through KeyguardManager
Here is some Kotlin code to help you out:
val kgManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
kgManager.isKeyguardSecure //true if the user set up their Lock Screen securely.
There is no such API, you have to catch the exception and handle it to ask user authentication when using pattern/PIN/password.
One solution if targeting API 23+ and only using Fingerprint is to use the FingerprintManager : https://developer.android.com/reference/android/hardware/fingerprint/FingerprintManager.html
You have an example on how to use it there:
https://github.com/deivitaka/AndroidFingerprintAPI
https://github.com/googlesamples/android-FingerprintDialog
Related
I was integrating azure AdB2c for my native android application, I have used SignInSignUp and
passwordReset userFlow for my current Application. Currently When I'm resetting the password, the password gets changed and redirect to app as expected, but when tries to relaunch the application after some time,MSAL is throwing out an exception ,which is messagecom.microsoft.identity.client.exception.MsalUiRequiredException: AADB2C90088: The provided grant has not been issued for this endpoint. Actual Value : B2C_1_SignInSignUp and Expected Value : B2C_1_PasswordReset . How can I handle during Such situation?
You are using seperate password reset and sign in/sign up flows. This means once the user performs password reset, the tokens are issued for the password reset policy. Later, once the access token expires, the refresh token is used to get a new access token. In this call, you pass in an account object (password reset), but perform the call against the sign in/up authority. This causes an error as the refresh token in the password reset account object can only be used against the password reset authority (policy).
To solve this, you can use the combined sign up/in/password reset journey.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/add-password-reset-policy?pivots=b2c-user-flow#self-service-password-reset-recommended
I am working on an app that uses Key Store Keys to enable authentication with the server. When the user logs in I am creating a key pair that requires Authentication to be used either by fingerprint or device credentials.
The problem I have is that I am trying for the keys to get invalidated every time the user changes the security in his device either by enrolling fingerprints or changing the PIN/PASSWORD/PATTERN.
I know that the Key specs have the setInvalidatedByBiometricEnrollment() method but from what I read it only invalidates the keys if there's a change in the biometrics, that doesn't help me if the user is only using device credentials. Furthermore, that method was added on API 24 and I am targetting devices starting with API 23.
This is the way I am creating the keys:
//Purposes of the key
int keyPurp =
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT |
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY;
//Init a builder for the key.
KeyGenParameterSpec.Builder keyBuilder = new KeyGenParameterSpec.Builder(keyAlias,keyPurp)
//We set the valid formats of the digests for signing
keyBuilder.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512);
//Require the user to authenticate and session expiry
keyBuilder.setUserAuthenticationRequired(true);
keyBuilder.setUserAuthenticationValidityDurationSeconds(10);
KeyGenParameterSpec keySpec = keyBuilder.build();
//Initialize the generator of the keys
generator.initialize(keySpec);
//Get the keys
generator.generateKeyPair();
Is there any Android API to detect changes in the Pin/Pattern/Password configuration?
Check out the docs for the isInvalidatedByBiometricEnrollment and setInvalidatedByBiometricEnrollment.
isInvalidatedByBiometricEnrollment
Returns true if the key is irreversibly invalidated when a new biometric is enrolled or all enrolled biometrics are removed. This has effect only for keys that require biometric user authentication for every use.
^ Important part is the last bit has effect only for keys that require biometric user authentication for every use.
setInvalidatedByBiometricEnrollment
Sets whether this key should be invalidated on biometric enrollment. This applies only to keys which require user authentication (see setUserAuthenticationRequired(boolean)) and if no positive validity duration has been set (see setUserAuthenticationValidityDurationSeconds(int), meaning the key is valid for biometric authentication only.
^ Important part there is if no positive validity duration has been set.
So if you want your keys to be invalidated by changes to biometry, they cannot have a duration attached to them. They must be single use.
We have noticed the keys actually cannot be used even if they have validity duration set to them, but you do not get correct Exception. And you cannot tell difference between a usage outside of duration period or if the key is invalidated.
Issue
Biometric authentication iris and face-detection is not prompting with
biometricPrompt.authenticate(**crypto**, promptInfo) call.
Source reference:
Securing data with BiometricPrompt (19 May 2019)
One Biometric API Over all Android (30 October 2019)
Biometrich API
Device used for testing:
Samsung S8 (Android OS 9)
Steps of Authentication I'm following:
val biometricPrompt = BiometricPrompt(...)
val promptInfo = BiometricPrompt.PromptInfo.Builder()...
biometricPrompt.authenticate(promptInfo) (PFA: option A, B)
and there is another authentication method which take cipher object to make sure
biometricPrompt.authenticate(crypto, promptInfo). (PFA: option C)
Everything worked just as expected with new and older API device support. Until unless realize tested application for other biometric authentication option iris and using face detection.
If I follow
biometricPrompt.authenticate(promptInfo) then application simply display authentication option based on user preference which he has to choose from Device Setting -> Biometric preference.
And perform authentication independently. (PFA: option A, B)
But if use biometricPrompt.**authenticate**(crypto, promptInfo) then it displays only fingerprint authentication option ONLY. For other preference option iris and face-detection, it does not display anything on authenticate(..) method call. (PFA: option C)
Question
Why other Biometric authentication is not prompting with crypto object authentication.
Some devices only have one form factor, some have many form factors. Which form factor your app ends up using isn't really up to you; it's up to the OEM implementation. As explained in this blog post, whether a form factor is Strong or Weak doesn't depend on your code -- the OEM decides. However, you can request that a device uses Strong authentication for your app by specifying a CryptoObject when you call authenticate().
What you are experiencing is that the OEMs of your devices decided to make Fingerprint the default for Strong biometrics. Therefore, when you pass in a CryptoObject to authenticate() those devices show the user the UI for Fingerprint.
Face-Id is considered as WEAK authenticator. If you set .setAllowedAuthenticators(BIOMETRIC_WEAK or DEVICE_CREDENTIAL) in BiometricPrompt Info and performs any Key based crypto operations. It will throw
java.lang.IllegalArgumentException: Crypto-based authentication is not supported for Class 2 (Weak) biometrics.
For crypto-based authentication only allowed authenticators are BIOMETRIC_STRONG or DEVICE_CREDENTIAL
Refer table here: https://source.android.com/docs/security/features/biometric
I have added Biometric Prompt in my Android app. So on app start, I am able to show prompt and if success is able to redirect user on the Dashboard screen. In case user failed I want to show System password as a secondary option to authenticate. How to do that with Biometric Prompt?
mBiometricManager = new BiometricManager.BiometricBuilder(FingerprintActivity.this)
.setTitle(getString(R.string.biometric_title))
.setSubtitle(getString(R.string.biometric_subtitle))
.setDescription(getString(R.string.biometric_description))
.setNegativeButtonText(getString(R.string.biometric_negative_button_text))
.build();
mBiometricManager.authenticate(FingerprintActivity.this);
on your biometric prompt add this
.setDeviceCredentialAllowed(true)
But check phone has a password/passcode setup with:
android.app.KeyguardManager.isDeviceSecure()
You can handle by extending BiometricPrompt.AuthenticationCallback, there are two main methods for handling fail state. onAuthenticationError and onAuthenticationFailed
onAuthenticationFailed
When the fingerprint doesn’t match with any of the fingerprints registered on the device, then this callback will be triggered.
onAuthenticationError
When an unrecoverable error has been encountered and the authentication process has completed without success, then this callback will be triggered. The callback is provided with an error code to identify the cause of the error
You can use Device administration API for showing system password in the case of Biometic auth fail.
I'm using this pattern lock view library: https://github.com/aritraroy/PatternLockView
In complete callback of this view, i can receive a string like "845321", a md5 or sha1.
Can i use this result and request the system for authenticating the result for me using the pattern pass users have set up in their phone.
That is not possible, sorry. The user has to authenticate with the device; you cannot supply authentication credentials on the user's behavlf.