mjwheatley / cordova-plugin-android-fingerprint-auth

A cordova plugin for fingerprint authentication using the hardware fingerprint scanner on devices running Android 6+
Apache License 2.0
168 stars 131 forks source link

No token returned when using PIN backup #85

Closed maleriepace closed 7 years ago

maleriepace commented 7 years ago

When I use the backup method, it doesn't seem that the password is encrypted and stored. Do you have an example of how withBackup should be implemented?

mjwheatley commented 7 years ago

Currently, it is that way by design. So you are saying you don't care if they authenticated with a fingerprint or the back up credentials, either way you want to encrypt or decrypt a token? If a user is going to authenticate via backup credentials, shouldn't they just use your login form instead? What is your particular use case? After all the main purpose of this plugin is fingerprint authentication. Perhaps you could display a message that says only fingerprint authentication is accepted if you receive withBackup: true from the plugin.

maleriepace commented 7 years ago

Thanks for the quick response! I am implementing an option to authenticate with a fingerprint or PIN to give users an easier, faster way to log in instead of typing in their password. I'm hoping to include the PIN option only because not all devices will have a fingerprint reader. I created a fork and have been trying to figure out how to get an authenticated cipher from the backup authentication response but with no success so far.

mjwheatley commented 7 years ago

ok, I just started looking into it as well. I think the key is looking at the CryptoObject. In onAuthenticated when authentication happens via fingerprint, there is a FingerprintManager.AuthenticationResult param available that has the CryptoObject that was set on the Fragment mFragment.setCryptoObject(new FingerprintManager.CryptoObject(mCipher)); So I am going to try creating a new CryptoObject in the same way if authentication occurred using the backup.

mjwheatley commented 7 years ago

Yep, that seemed to do the trick.

maleriepace commented 7 years ago

Wow, thanks!

maleriepace commented 7 years ago

Actually, I'm still getting an illegalblocksizeexception here when encrypting using a PIN. Are you seeing that?

mjwheatley commented 7 years ago

Probably because there are 2 flows to get to the backup credentials.

    • isFingerprintAvailable() // true
      • secret key != null
        • !initCipher()
          • !mDisableBackup
    • isFingerprintAvailable() // false
      • useBackupLockScreen() // true

In both cases the cipher has not been initialized and the secret key could may not have been generated.

Do you know which user flow is initiating the backup credentials activity ( 1 or 2)?

It probably worked for me because I had previously authenticated with a fingerprint and created a secret key and initialized my cipher.

So to make this work properly I will need to insure those both get initialized if not isFingerprintAvailable().

mjwheatley commented 7 years ago

Please test the commit I just pushed and let me know if that helps with the issue. If so, I will publish the fix.

maleriepace commented 7 years ago
isFingerprintAvailable() // true
secret key != null
!initCipher()
!mDisableBackup

I've been unable to get getSecretKey to return a null key or initCipher to return false in my testing.

isFingerprintAvailable() // false
useBackupLockScreen() // true

This flow doesn't seem to work at all. I never get the response to hit any breakpoints in onActivityResult found in either FingerprintAuth or FingerprintAuthenticationDialogFragment. Looks like in this scenario, the fragment is never initialized, which explains why the breakpoint isn't hit in that class, but I don't see why I can't get into onActivityResult in FingerprintAuth. After the correct PIN is entered, the PIN screen closes with no response and no messages in the log.

mjwheatley commented 7 years ago

Sorry, Those flows may have hard to follow.

Let me try to clarify. My recent code change will create a secret key no matter what now, so it will error out if it can't generate the key. Then if the isFingerprintAuthAvailable() is false, it will check if the lock screen is secure, useBackupLockscreen() is true. Finally it will callshowAuthenticationScreen(). That method starts the user credentials activity with request code REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS. When that activity finishes you should get a breakpoint to hit in onActivityResult() in FingerprintAuth.java.

maleriepace commented 7 years ago

Hey, sorry for not getting back to you right away. I've been doing some testing and tinkering on my end. I think I'm going to have to either scrap the PIN idea or figure out a different way to do it. I was originally looking to do something similar to the Mint or other banking apps where you can actually set your own PIN to authenticate with, but I figured the unlocking PIN would be ok instead since that's what your plugin uses.

If I use the plugin on a device with no fingerprint ability, I get a InvalidAlgorithmParameterException when generating the key because there are no fingerprints registered. Thanks for your help! I think I'm just going to use fingerprint only for now.

walternicholas commented 7 years ago

Thanks mjwheatley for writing this plugin!

Just added it to my app and I'm having the same problem as maleriepace

If I attempt to "USE BACKUP" (device's PIN unlock) to encrypt or decrypt, I get ILLEGAL_BLOCK_SIZE_EXCEPTION

Going to have to set disableBackup = true (not ideal) until we can get this fixed.

Let me know if there is any way to help test.

mjwheatley commented 7 years ago

Hi @walternicholas, What device were you testing on? Was it with or without fingerprint hardware? If with, were there fingerprints registered on the device or not?

mjwheatley commented 7 years ago

If you are able to debug, can you provide the line of code that is causing the exception?
Are you seeing the error message printed by the code below in logcat?

catch (IllegalBlockSizeException e) {
            Log.e(TAG, "Failed to encrypt the data with the generated key: "
                    + "IllegalBlockSizeException: " + e.toString());
            errorMessage = PluginError.ILLEGAL_BLOCK_SIZE_EXCEPTION.name();
        }
walternicholas commented 7 years ago

Testing on an LG Nexus 5X and also an OnePlus 3 (https://oneplus.net/3).

Both have fingerprint hardware. Both had registered fingerprints. Same results on both.

I'll hop in and do some debugging and get back to you with which line is throwing that error.

walternicholas commented 7 years ago

@mjwheatley

Yes that is the exact error I'm seeing printed in logcat, coming from the block of code you posted (623-626 in FingerprintAuth.java).

This error when I am trying to decrypt appears, after these 3 steps:

  1. Give the fingerprint scanner a finger which isn't registered.
  2. Tap "USE BACKUP" button which appears after first fail.
  3. Enter the correct 4-digit backup PIN for unlocking the device.
mjwheatley commented 7 years ago

So you have to have a failed attempt first for the backup button to appear? Is this device specific or a custom implementation. The backup button is always present when testing on my Nexus 6p.

mjwheatley commented 7 years ago

Is the e.toString() printing out any additional information?

walternicholas commented 7 years ago

Actually no that was my mistake, I didn't notice the USE BACKUP button on my first try. Was editing my comment to fix that when you posted. I still get the same problem, encrypting or decrypting, with or without first providing a wrong fingerprint before hitting USE BACKUP.

walternicholas commented 7 years ago

From logcat: E/FingerprintAuth: Failed to encrypt the data with the generated key: IllegalBlockSizeException: javax.crypto.IllegalBlockSizeException

mjwheatley commented 7 years ago

Can you tell which line in the try block, lines 578 - 618, is triggering the catch?

mjwheatley commented 7 years ago

I'm guessing that it may be line 605-606

bytes = cryptoObject.getCipher()
                            .doFinal(Base64.decode(mClientSecret, Base64.NO_WRAP));

Referencing https://developer.android.com/reference/javax/crypto/Cipher.html

Public methods doFinal

int doFinal (byte[] input, 
                int inputOffset, 
                int inputLen, 
                byte[] output)

Throws IllegalBlockSizeException if this cipher is a block cipher, no padding has been requested (only in encryption mode), and the total input length of the data processed by this cipher is not a multiple of block size; or if this encryption algorithm is unable to process the input data provided.

mjwheatley commented 7 years ago

@walternicholas if possible, perhaps we can arrange a time to investigate this together. Would you be agreeable to that?

walternicholas commented 7 years ago

@mjwheatley Yeah I'd be happy to help investigate. What time works for you?

mjwheatley commented 7 years ago

Contact me at mattjwheatley@gmail.com and we can coordinate.

mjwheatley commented 7 years ago

Fixed by setting userAuthRequired to false and regenerating secret key by uninstalling and reinstalling.
Releasing new version 1.4.0 See release notes for changes.

jenkinssgs commented 5 years ago

Hi, I need to Re-Design the Authentication window of FingerprintAuth, Is there any way to do. Your Helps would be greatly appreciated. Thanks.

mjwheatley commented 5 years ago

You can fork the repository and edit the layout. https://github.com/mjwheatley/cordova-plugin-android-fingerprint-auth/blob/master/res/android/layout/fingerprint_dialog_content.xml