Giter Site home page Giter Site logo

mauin / rxfingerprint Goto Github PK

View Code? Open in Web Editor NEW
378.0 19.0 84.0 515 KB

Android Fingerprint authentication and encryption with RxJava

License: Apache License 2.0

Java 100.00%
rxjava rxjava2 fingerprint fingerprint-authentication fingerprint-sensor encryption android

rxfingerprint's Introduction

RxFingerprint: Android Fingerprint Authentication and Encryption in RxJava2

RxFingerprint wraps the Android Fingerprint APIs (introduced in Android Marshmallow) and makes it easy to:

  • Authenticate your users with their fingerprint
  • Encrypt and decrypt their data with fingerprint authentication

Learn more about the Android Fingerprint APIs at developer.android.com.

This library has a minSdkVersion of 15, but will only really work on API level 23. Below that it will provide no functionality due to the missing APIs.

Usage

To use RxFingerprint in your project, add the library as a dependency in your build.gradle file:

dependencies {
    compile 'com.mtramin:rxfingerprint:2.2.1'
}

Furthermore, you have to declare the Fingerprint permission in your AndroidManifest.xml:

<uses-permission android:name="android.permission.USE_FINGERPRINT" />

Checking for availability

Before using any fingerprint related operations it should be verified that RxFingerprint can be used by calling:

if (RxFingerprint.isAvailable(this)) {
    // proceed with fingerprint operation
} else {
    // fingerprint is not available
}

Reasons for RxFingerprint to report that it is not available include:

  • The current device doesn't have a fingerprint sensor
  • The user is not using the fingerprint sensor of the device
  • The device is running an Android version that doesn't support the Android Fingerprint APIs

Authenticating a user with their fingerprint

To authenticate the user with their fingerprint, call the following:

Disposable disposable = RxFingerprint.authenticate(this)
                .subscribe(fingerprintAuthenticationResult -> {
                    switch (fingerprintAuthenticationResult.getResult()) {
                        case FAILED:
                            setStatusText("Fingerprint not recognized, try again!");
                            break;
                        case HELP:
                            setStatusText(fingerprintAuthenticationResult.getMessage());
                            break;
                        case AUTHENTICATED:
                            setStatusText("Successfully authenticated!");
                            break;
                    }
                }, throwable -> {
                    Log.e("ERROR", "authenticate", throwable);
                });

By subscribing to RxFingerprint.authenticate(Context) the fingerprint sensor of the device will be activated and it will wait for the user to touch it with one of their registered fingerprints. Should the device not contain a fingerprint sensor or the user has not enrolled any fingerprints, onError will be called.

After successful authentication or a recoverable error (e.g. the sensor could not read the fingerprint clearly) onNext will be called. You should check the result to see if the authentication was successful. In the case of a recoverable error the value provded to onNext contains a helpful message that can be shown to the user and the user can try again.

By disposing the Disposable, the fingerprint sensor will be disabled again with no result.

Encryption-and-decryption

Usage of the Encryption and decryption features of RxFingerprint are very similar to simple authentication calls.

RxFingerprint supports encryption with both the AES and RSA encryption standards. They differ in the way the user needs to interact with their fingerprint sensor. For encryption and decryption the same EncryptionMethod should be used. Otherwise the encrypted data cannot be decrypted.

Encryption and Decryption in RxFingerprint is backed by the Android KeyStore System.

After the encryption step all results will be Base64 encoded for easier transportation and storage.

AES

When choosing AES for encryption and decryption the user will have to approve both actions by authentication with their fingerprint by touching the fingerprint sensor. The encryption then relies on the Advanced Encryption Standard with a 256-bit keysize.

The usage flow for AES is as follows:

  • Call RxFingerprint.encrypt(EncryptionMethod.AES, ...) to initialize the encryption flow

  • User authenticates by touching the fingerprint sensor

  • Store the encrypted data returned in the onNext callback

  • Call RxFingerprint.decrypt(EncryptionMethod.AES, ...) to initialize the decryption flow

  • User authenticates by touching the fingerprint sensor

  • Receive the decrypted data in the onNext callback

RSA

RSA encryption allows you to encrypt a value without any user action. The data to encrypt can be encrypted and a user won't need to authenticate oneself by touching the fingerprint sensor. The encrypted data can only be decrypted again when the user authenticates by using the fingerprint sensor on their device.

The usage flow for AES is as follows:

  • Call RxFingerprint.encrypt(EncryptionMethod.RSA, ...) to initialize the encryption flow

  • Store the encrypted data returned in the onNext callback

  • Call RxFingerprint.decrypt(EncryptionMethod.RSA, ...) to initialize the decryption flow

  • User authenticates by touching the fingerprint sensor

  • Receive the decrypted data in the onNext callback

Encrypting and decrypting values

Disposable disposable = RxFingerprint.encrypt(EncryptionMethod.RSA, this, keyName, stringToEncrypt)
                   .subscribe(encryptionResult -> {
                       switch (encryptionResult.getResult()) {
                           case FAILED:
                               setStatusText("Fingerprint not recognized, try again!");
                               break;
                           case HELP:
                               setStatusText(encryptionResult.getMessage());
                               break;
                           case AUTHENTICATED:
                               setStatusText("Successfully authenticated!");
                               break;
                       }
                   }, throwable -> {
                       Log.e("ERROR", "authenticate", throwable);
                       setStatusText(throwable.getMessage());
                   });

RxFingerprint.encrypt(EncryptionMethod, Context, String, String) takes the String you want to encrypt (which might be a token, user password, or any other String) and a key name. The given String will be encrypted with a key in the Android KeyStore and returns an encrypted String. The key used in the encryption is only accessible from your own app. Store the encrypted String anywhere and use it later to decrypt the original value by calling:

Disposable disposable = RxFingerprint.decrypt(EncryptionMethod.RSA, this, keyName, encryptedValue)
                    .subscribe(decryptionResult -> {
                        switch (decryptionResult.getResult()) {
                            case FAILED:
                                setStatusText("Fingerprint not recognized, try again!");
                                break;
                            case HELP:
                                setStatusText(decryptionResult.getMessage());
                                break;
                            case AUTHENTICATED:
                                setStatusText("decrypted:\n" + decryptionResult.getDecrypted());
                                break;
                        }
                    }, throwable -> {
                        //noinspection StatementWithEmptyBody
                        if (RxFingerprint.keyInvalidated(throwable)) {
                            // The keys you wanted to use are invalidated because the user has turned off his
                            // secure lock screen or changed the fingerprints stored on the device
                            // You have to re-encrypt the data to access it
                        }
                        Log.e("ERROR", "decrypt", throwable);
                        setStatusText(throwable.getMessage());
                    });

Be aware that all encryption keys will be invalidated once the user changes their lockscreen or changes any of their enrolled fingerprints. If you receive an onError event during decryption check if the keys were invalidated with RxFingerprint.keyInvalidated(Throwable) and prompt the user to encrypt their data again.

Once the encryption keys are invalidated RxFingerprint will delete and renew the keys in the Android Keystore on the next call to RxFingerprint.encrypt(...).

Best-practices

To prevent errors and ensure a good user experience, make sure to think of these cases:

  • Before calling any RxFingerprint authentication, check if the user can use fingerprint authentication by calling: RxFingerprint.isAvailable(Context) or RxFingerprint.isUnavailable(Context)
  • Always check for recoverable errors in any onNext events and provide the user with the given Error message in the result.
  • If keys were invalidated due to the user changing their lockscreen or enrolled fingerprints provide them with a way to encrypt their data again.

Dependencies

RxFingerprint brings the following dependencies:

  • RxJava2
  • Android Support Annotations

Bugs and Feedback

For bugs, questions and discussions please use the Github Issues.

LICENSE

Copyright 2015-2017 Marvin Ramin.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

rxfingerprint's People

Contributors

andretietz avatar commonsguy avatar jalcine avatar mato666 avatar mauin avatar nullpointerr avatar serj-lotutovici avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rxfingerprint's Issues

Use smart lock as fallback

Hey there,

Since not all the Android devices provide fingerprint scanner and even some that do, are not setup by the device owner, would it be interesting to provide an out of the box fallback functionality that would use the smart lock authentication instead?

A possible flow would be as follows:

  1. Check for fingerprint support
  2. Check for fingerprint enrolled
    1. If enrolled use it for accessing the KeyStore
    2. else use PIN/pattern/password auth for accessing the KeyStore

I understand that without fingerprint the authenticated device holder is granting access to all the keys for a period of time, instead of having specific key bound to the fingerprint authentication, but as I said it's a fallback.

Is it something you would consider introducing to this library @Mauin?

Thanks

Callback is not called second time on error

When you start example and use unregistered finger to cause an error, the callback(Consumer) is not called second time. But it works fine every time you use registered finger.

I use dispose() inside callback to deinit sensor. After that second call works.

Problems with orientation changes during listening

Hi Mauin,

do you experience problems on changing the orientation while listening?

I am calling RxFingerprint.authenticate(this) in onResume on my activity and store the subscription in a member variable.
Within the onPause method I unsubsribe my fingerprintObersable by fingerprintObersable.unsubscribe and set the reference to null.

I get this Exception in catlog as debug info:

Fingerprint operation canceled.
at com.mtramin.rxfingerprint.FingerprintObservable$1.onAuthenticationError(FingerprintObservable.java:76)
at android.support.v4.hardware.fingerprint.FingerprintManagerCompat$Api23FingerprintManagerCompatImpl$1.onAuthenticationError(FingerprintManagerCompat.java:290)
at android.support.v4.hardware.fingerprint.FingerprintManagerCompatApi23$1.onAuthenticationError(FingerprintManagerCompatApi23.java:86)
at android.hardware.fingerprint.FingerprintManager$MyHandler.sendErrorResult(FingerprintManager.java:721)
at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage(FingerprintManager.java:695)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

and those debug messages in logcat:

10-09 20:53:03.673 1263-1263/? V/fingerprintd: authenticate(sid=0, gid=0)
10-09 20:53:09.774 1263-1263/? V/fingerprintd: stopAuthentication()
10-09 20:53:09.774 1263-1263/? D/FingerprintHal: ----------------> fingerprint_cancel ----------------->
10-09 20:53:09.774 1263-1263/? D/fingerprintd: onError(5)
10-09 20:53:09.778 1263-1263/? V/fingerprintd: authenticate(sid=0, gid=0)
10-09 20:53:18.757 1263-1263/? V/fingerprintd: authenticate(sid=0, gid=0)
10-09 20:55:36.335 1568-1583/system_process I/ActivityManager: Config changes=480 {1.0 310mcc260mnc en_US ldltr sw411dp w689dp h387dp 420dpi nrml land finger -keyb/v/h -nav/h s.7}
10-09 20:55:36.377 1263-1263/? V/fingerprintd: stopAuthentication()
10-09 20:55:36.377 1263-1263/? D/FingerprintHal: ----------------> fingerprint_cancel ----------------->
10-09 20:55:36.377 1263-1263/? D/fingerprintd: onError(5)
10-09 20:55:36.429 1263-1263/? V/fingerprintd: authenticate(sid=0, gid=0)
10-09 20:55:36.432 1263-1263/? V/fingerprintd: stopAuthentication()
10-09 20:55:36.432 1263-1263/? D/FingerprintHal: ----------------> fingerprint_cancel ----------------->
10-09 20:55:36.432 1263-1263/? D/fingerprintd: onError(5)

It would be great if you can help me keep using this library. I just considered trying an other one but I really love the Rx'ness of yours 👍

Thanks,
Moritz

RxFingerprint.keyInvalidated() requires SDK 23+, but what is the alternative to detecting key invalidation on SDK <23?

I've recently upgraded to the new RC (3.0.0-RC-1)

Because RxFingerprint.keyInvalidated was marked with an annotation @RequiresApi(23), when detecting errors, I now have to write something like so:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && RxFingerprint.keyInvalidated(throwable)) {
    // The keys you wanted to use are invalidated because the user has turned off her/his
    // secure lock screen or changed the fingerprints stored on the device
    // You have to re-encrypt the data to access it
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && throwable is InvalidKeyException) {
    // Is InvalidKeyException the right exception to catch here??
}

Could you write up some documentation on what to do in the case of a key being invalidated when the SDK is less than 23, since we can't use RxFingerprint.keyInvalidated()?
This would help devs using this library know when to force users to re-authenticate when their device is pre-23.

Or maybe RxFingerprint.keyInvalidated() could be written to automatically handle pre-23 devices so that developers don't have to write this code themselves and keyInvalidated() could catch all states where the developer needs to force a user to re-authenticate. I'm not sure if this is possible.

KeyPermanentlyInvalidatedException on encrypt()

Hey,

I'm using RxFingerprint (1.2.2) encryption / decryption capabilities and I'm currently struggling with the case where key is invalidated. Here is the flow of what I'm doing :

  1. Launch the activity => Ask user for some data => Encrypt that data => Save the encrypted data
  2. Remove the fingerprint used for the previous encryption, then add a new one
  3. Re-launch the activity => Decrypt the data => KeyPermanentlyInvalidatedException (that's fair) => Erase the encrypted data
  4. Re-ask user for some data => Re-encrypt that data => KeyPermanentlyInvalidatedException (that does not seems right ?)

So it seems that I can't re-use encryption at all after a KeyPermanentlyInvalidatedException. Am I missing something and if not what could be the cause of this result ?

java.lang.ClassCastException

I am not able to use AES encryption. (Device: Samsung S8, OS version: 8.0, library version: 2.2.1)

Usage:

    override fun encrypt(key: String, token: String): Observable<FingerprintScanResult> {
        return RxFingerprint.encrypt(EncryptionMethod.AES, context, key, token).map {
            fingerprintResultAdapter.toDomain(it)
        }
    }

Crash:

Caused by: java.lang.ClassCastException: android.security.keystore.AndroidKeyStoreRSAPrivateKey cannot be cast to javax.crypto.SecretKey
     at com.mtramin.rxfingerprint.AesCipherProvider.getKey(AesCipherProvider.java:60)
     at com.mtramin.rxfingerprint.AesCipherProvider.findOrCreateKey(AesCipherProvider.java:54)
     at com.mtramin.rxfingerprint.AesCipherProvider.cipherForEncryption(AesCipherProvider.java:75)
     at com.mtramin.rxfingerprint.CipherProvider.getCipherForEncryption(CipherProvider.java:84)
     at com.mtramin.rxfingerprint.AesEncryptionObservable.initCryptoObject(AesEncryptionObservable.java:83)

Am I missing something or it's really issue?

OnePlus 3 capacitive button dismiss the app

I have implemented fingerprint login to my app with RxFingerprint. Now I found that the fingerprint sensor on OnePlus 3 is placed on the home button that is, opposite to other phones, touch button (not clicky one). So when the user tries to login with his fingerprint, he touch the home button, the app goes to the background instead of read fingerprint and login into the app.

I'm curious, if I missed some step that is handling this situation, or if there have to be some workaround to fix this issue?

As I understand in normal implementation according to Google Sample it works correctly (it is working in other apps on OP3) - listening for fingerprint should disable home button click in that case.

UPDATE:
One of my friend tried my FP login on his OP3 and it worked flawlessly. But other users are complaining that it is suspending the app.

IOS equal

Hi
have RxFingerprint an IOS equal?

Offer char[] Option For Data to encrypt() and decrypt()

The encrypt() method takes the cleartext data as a String; the decrypt() method provides the decrypted cleartext data as a String. The problem in Java is that strings are immutable, which means we cannot forcibly clear their contents.

In some cases, the cleartext data is the actual data you are acting upon (e.g., you are encrypting/decrypting a JSON string, where the JSON represents your app's actual data). In that case, your cleartext data will be around as long as your app needs it anyway.

In some cases, though, the cleartext data is something that you would like to get rid of quickly. For example, perhaps the cleartext data is a generated passphrase to use with SQLCipher for Android or some other non-keystore encrypted container. In this case, it would be far preferable for the cleartext data to be char[] instead of String, as we can change the bytes of the char[] to erase the cleartext data once we are done with it.

For example, you could have:

  • encrypt() variants that take a char[] for toEncrypt
  • have FingerprintDecryptionResult hold a char[] for the decrypted data, with a getter method to retrieve it, and modifying getDecrypted() to convert the char[] into a String

From what I can tell, those changes should keep a compatible API with what you have, while still offering char[] support for those who need it.

Anyway, it's just an idea. Thanks for writing this library!

FingerprintAuthenticationException

I just got error log in Fabric. I don't have more information about this. Please advice me how to fix this if you can. Thanks

Fatal Exception: com.mtramin.rxfingerprint.data.FingerprintAuthenticationException
Vingerafdrukbewerking geannuleerd.
 Raw Text
com.mtramin.rxfingerprint.FingerprintObservable$2.onAuthenticationError (FingerprintObservable.java:98)
android.hardware.fingerprint.FingerprintManager$MyHandler.sendErrorResult (FingerprintManager.java:859)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:776)

NPE on Xiaomi MI 5s

Fatal Exception: java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String java.lang.CharSequence.toString()' on a null object reference at com.mtramin.rxfingerprint.FingerprintObservable$2.onAuthenticationError(FingerprintObservable.java:89) at android.hardware.fingerprint.FingerprintManager$MyHandler.sendErrorResult(FingerprintManager.java:848) at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage(FingerprintManager.java:813) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:163) at android.app.ActivityThread.main(ActivityThread.java:6321) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:880) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:770)

Recently new crashes in production seemingly from RxFingerprint

Hi, we've been using RxFingerprint for over a year and ne'er once saw a crash. On June 20th, it began crashing frequently (46 times impacting 21 users). Here's the trace:

at io.reactivex.internal.observers.LambdaObserver.a_ (LambdaObserver.java:32)
at io.reactivex.internal.observers.BasicFuseableObserver.a_ (BasicFuseableObserver.java:13)
at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.b (ObservableCreate.java:17)
at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.dispose (ObservableCreate.java)
or .onError (ObservableCreate.java)
or .onNext (ObservableCreate.java)
or .setCancellable (ObservableCreate.java)
or .setDisposable (ObservableCreate.java)
at com.mtramin.rxfingerprint.FingerprintObservable$2.onAuthenticationError (FingerprintObservable.java:15)
at android.hardware.fingerprint.FingerprintManager$MyHandler.sendErrorResult (FingerprintManager.java:1285)
at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage (FingerprintManager.java:1230)
at android.os.Handler.dispatchMessage (Handler.java:105)
at android.os.Looper.loop (Looper.java:164)
at android.app.ActivityThread.main (ActivityThread.java:6938)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:327)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)

I've verified all usages of RxFingerprint and confirm they all have onError() handlers. Any idea how we can explore this further?

Question - Some explanation on RSA implementation

Hi:
I am new to cryptography and thanks for the great library.

I have two questions on the RSA implementation of this lib.

Invalidate keys after enrolling an additional fingerprint

After enroling an additional fingerprint, there should be option to invalidate stored keys. In Android 6 this is default behaviour, but on Android 7 you must set this in KeyGenParameterSpec builder (setInvalidatedByBiometricEnrollment).

Please see following post: https://benlikestoco.de/notable-fingerprint-api-changes-in-android-7-cc3ec99a11c4

You could maybe open option for defining some attributes, when building KeyGenParameterSpec. Anyway I thing setInvalidatedByBiometricEnrollment(true) should be set by default.

Thanks.

return a reason for RxFingerprint.IsAvailable

when a fingerprint is unavailable there can be several reasons, the hardware is not supported, no enrolled fingerprint.....

I want to show a reason for the user because he might be able to do something about it, (e.g. enroll a fingerprint, buy a new device...)

so instead of checking every reason one by one, just send the reason so developers can act accordingly

Encrypt without fingerprint authentication

I am getting the token from the backend I am looking to encrypt it using this library and store it in SharedPrefrence and on subsequent Logon I would like to read the encrypted token from the shared preference and decrypt using the Fingerprint and send the decrypted token to backend
It would be great if you could show some lights

Unexposed Internal Crash

We are seeing a crash in the latest version of the library that isn't being exposed for us to handle. It seems to be related to changing the fingerprint in Android settings.

Because the crash isn't exposed to our code at all, we have no way of catching the exception and handling it in some way. It forces a crash on our application, and there isn't anything we can do.

Fatal Exception: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by java.lang.reflect.InvocationTargetException
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by javax.crypto.IllegalBlockSizeException
       at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:519)
       at javax.crypto.Cipher.doFinal(Cipher.java:2056)
       at com.mtramin.rxfingerprint.AesEncryptionObservable.onAuthenticationSucceeded(AesEncryptionObservable.java:95)
       at com.mtramin.rxfingerprint.FingerprintObservable$2.onAuthenticationSucceeded(FingerprintObservable.java:104)
       at android.hardware.fingerprint.FingerprintManager$MyHandler.sendAuthenticatedSucceeded(FingerprintManager.java:876)
       at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage(FingerprintManager.java:824)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6290)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by android.security.KeyStoreException: Key user not authenticated
       at android.security.KeyStore.getKeyStoreException(KeyStore.java:666)
       at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.update(KeyStoreCryptoOperationChunkedStreamer.java:132)
       at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:217)
       at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
       at javax.crypto.Cipher.doFinal(Cipher.java:2056)
       at com.mtramin.rxfingerprint.AesEncryptionObservable.onAuthenticationSucceeded(AesEncryptionObservable.java:95)
       at com.mtramin.rxfingerprint.FingerprintObservable$2.onAuthenticationSucceeded(FingerprintObservable.java:104)
       at android.hardware.fingerprint.FingerprintManager$MyHandler.sendAuthenticatedSucceeded(FingerprintManager.java:876)
       at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage(FingerprintManager.java:824)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6290)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

Allow setting setUserAuthenticationValidityDurationSeconds

Hello,

I want to know if its possible to set setUserAuthenticationRequired and setUserAuthenticationValidityDurationSeconds from the dependence. From that what I can see, I don't have the possibility to set this, is that right? If yes, how??

Thanks in advance

Add support for deleting default keystore entry

Right now you can only delete the secretKey but not the default keystore entry. This is useful for app that has optional fingerprint feature where user can turn it off anytime. When the user turn off the fingerprint feature we should delete the secretKey and keystore entry.

Deleting the keystore entry is easy to implement but we need something more convenient. I think we should include it in this library.

Its already implemented in CipherProvider.

private static void removeKey(String keyName) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
  if (keyExists(keyName)) {
    KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
    keyStore.load(null);
    keyStore.deleteEntry(keyName);
  }
}

I propose something like:

RxFingerprint.removeKey() // Default KeyName
RxFingerprint.removeKey("CUSTOMKEY") // Custom KeyName

What do you guys think?

Is there an "On start decrypt listener"

I need a way to understand when the method decrypt starts.
Decryption seems to be very slow (I'm testing on a nexus 6p and it takes like 1 second to finish). I have to add a spinner in order to give to the user a feedback that something happens.

thanks for your support and sorry for bad english.

java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference

Thanks for your great work.
I'm using your lib for a while and run some tests but currently getting the following error when trying to init RxFingerprint.decrypt()

java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference at android.os.Parcel.readException(Parcel.java:1626) at android.os.Parcel.readException(Parcel.java:1573) at android.hardware.fingerprint.IFingerprintService$Stub$Proxy.authenticate(IFingerprintService.java:300) at android.hardware.fingerprint.FingerprintManager.authenticate(FingerprintManager.java:601) at android.hardware.fingerprint.FingerprintManager.authenticate(FingerprintManager.java:574) at android.hardware.fingerprint.FingerprintManager.authenticate(FingerprintManager.java:552) at com.mtramin.rxfingerprint.FingerprintObservable.subscribe(FingerprintObservable.java:81) at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40) at io.reactivex.Observable.subscribe(Observable.java:10179) at io.reactivex.Observable.subscribe(Observable.java:10165) at io.reactivex.Observable.subscribe(Observable.java:10096) at gui.Login.initFingerprints(Login.java:179) at gui.Login.onResume(Login.java:1179) at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1287) at android.app.Activity.performResume(Activity.java:7015) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4210) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4323) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1865) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:7325) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

Source

Disposable disposable = RxFingerprint.decrypt(this, "k", AppSettings.getFingerprintHash(getAppContext())). subscribe(fingerprintDecryptionResult -> { //line 179 if(fingerprintDecryptionResult != null){ switch(fingerprintDecryptionResult.getResult()){ case FAILED: setStatusText("Fingerprint not recognized, try again!"); break; case HELP: setStatusText(fingerprintDecryptionResult.getMessage()); break; case AUTHENTICATED: setStatusText("decrypted:\n" + fingerprintDecryptionResult.getDecrypted()); break; } } }, throwable -> { //noinspection StatementWithEmptyBody if(RxFingerprint.keyInvalidated(throwable)){ // The keys you wanted to use are invalidated because the user has turned off his // secure lock screen or changed the fingerprints stored on the device // You have to re-encrypt the data to access it } Log.e("ERROR", "decrypt", throwable); });

Any idea where it comes from?

pass fingerprint reason (int) for advanced functionality

pass some raw data in case we want to use it, it might be a use case the library does not cover which will not cause it to be useless.

e.g. FINGERPRINT_ACQUIRED_GOOD... , FINGERPRINT_ERROR_UNABLE_TO_PROCESS, and so on.

In most case it won't be used but that's an important data that might be used

Recover from Fingerprint operation canceled

Hey,

This could be the fact that I am new to RxJava but when I cancel the fingerprint I get the exception com.mtramin.rxfingerprint.data.FingerprintAuthenticationException: Fingerprint operation canceled. that I cannot seem to fail gracefully with. I have tried putting error handlers in two places, neither of which seem to be working correctly. Below is my code

fingerprintDisposable = RxFingerprint.authenticate(this)
                .onErrorReturn(new Function<Throwable, FingerprintAuthenticationResult>() {
                    @Override
                    public FingerprintAuthenticationResult apply(Throwable throwable) throws Exception {
                        try {
                            return new FingerprintAuthenticationResult(FingerprintResult.FAILED, null);
                        } catch(Exception e) {
                            Log.e("ERROR", e.getLocalizedMessage());
                            return new FingerprintAuthenticationResult(FingerprintResult.FAILED, null);
                        }
                    }
                })
                .subscribe(new Consumer<FingerprintAuthenticationResult>() {
                    @Override
                    public void accept(FingerprintAuthenticationResult fingerprintAuthenticationResult) throws Exception {
                        switch (fingerprintAuthenticationResult.getResult()) {
                            case FAILED:
                                Toast.makeText(SignInActivity.this, R.string.fingerprint_not_recognized, Toast.LENGTH_LONG);
                                break;
                            case HELP:
                                Toast.makeText(SignInActivity.this, fingerprintAuthenticationResult.getMessage(), Toast.LENGTH_LONG);
                                break;
                            case AUTHENTICATED:
                                ((ImageView) dialog.findViewById(R.id.fingerprint_icon)).setImageResource(R.drawable.fingerprint_ok);
                                ((TextView) dialog.findViewById(R.id.touch_sensor_tv)).setText(R.string.fingerprint_recognized);

                                onSignIn(mSessionService.getFingerprintUsername(), mSessionService.getFingerprintPassword());
                                break;
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Log.e("ERROR", "", throwable);
                    }
                });

Lib crashes on minimize

com.mtramin.rxfingerprint.data.FingerprintAuthenticationException: Fingerprint operation canceled. at com.mtramin.rxfingerprint.FingerprintObservable$1.onAuthenticationError(FingerprintObservable.java:83) at android.support.v4.hardware.fingerprint.FingerprintManagerCompat$Api23FingerprintManagerCompatImpl$1.onAuthenticationError(FingerprintManagerCompat.java:290) at android.support.v4.hardware.fingerprint.FingerprintManagerCompatApi23$1.onAuthenticationError(FingerprintManagerCompatApi23.java:90) at android.hardware.fingerprint.FingerprintManager$MyHandler.sendErrorResult(FingerprintManager.java:721) at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage(FingerprintManager.java:695) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Support Log customization

With more and more warning/info level Log messages in the Library it would be a good idea to support setting a custom Logger or letting users disable Logs completely.

Proguard Error

I am using version 1.2.2 and getting the following error.

Warning: com.mtramin.rxfingerprint.FingerprintObservable$$Lambda$1: can't find referenced class java.lang.invoke.LambdaForm$Hidden

Works fine on adding the following rule to proguard :

#rxFingerprint
-dontwarn com.mtramin.rxfingerprint.**

javax.crypto.IllegalBlockSizeException on few devices

For some reason devices like ZTE V6 Plus (6.0) throw javax.crypto.IllegalBlockSizeException where others, mainly mainstream Samsung, Huawei, Sony work as expected.

RxFingerprint.encrypt(EncryptionMethod.AES, context, "a", "1234567890123456").subscribe()

At least one fingerprint has been enrolled.
Any ideas?

detect new fingerprint added

Hi Mauin.
I have a popupDialog which should disappear when new fingerprint is added in Settings without calling encrypt or decrypt on the beginning. Idea how to check this?

If I am using if (RxFingerprint.keyInvalidated(new Throwable)) {} it gives me false all the time even new fingerprint is added.
Help?

IllegalBlockSizeException on some devices

We have successfully implemented fingerprint authentication using RxFingerprint. But we have encountered some problem on few devices that throws IllegalBlockSizeException when using the encrypt api.

Here's the list of devices we got from fabric:

  • Flash Plus 2
  • Infinix_X521
  • HOT 4
  • Lenovo K5 Note
  • Flare X2
  • Infinix NOTE 3 Pro

Using the code below throws IllegalBlockSizeException when user enters fingerprint.

RxFingerprint.encrypt(getActivity(), "sometoken")
                .compose(bindToLifecycle())
                .subscribe(result -> {
                    switch (result.getResult()) {
                        case AUTHENTICATED:
                            ...
                            break;
                    }
                }, error -> {
                    // Few devices throws IllegalBlockSizeException when user enters fingerprint
                });
Non-fatal Exception: javax.crypto.IllegalBlockSizeException
       at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:486)
       at javax.crypto.Cipher.doFinal(Cipher.java:1502)
       at com.mtramin.rxfingerprint.FingerprintEncryptionObservable.onAuthenticationSucceeded(Unknown Source:112)
       at com.mtramin.rxfingerprint.FingerprintObservable$2.onAuthenticationSucceeded(Unknown Source:114)
       at android.hardware.fingerprint.FingerprintManager$MyHandler.sendAuthenticatedSucceeded(FingerprintManager.java:882)
       at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage(FingerprintManager.java:834)
       at android.os.Handler.dispatchMessage(Handler.java:111)
       at android.os.Looper.loop(Looper.java:207)
       at android.app.ActivityThread.main(ActivityThread.java:5765)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
Caused by android.security.KeyStoreException: Key user not authenticated
       at android.security.KeyStore.getKeyStoreException(KeyStore.java:650)
       at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.update(KeyStoreCryptoOperationChunkedStreamer.java:132)
       at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:217)
       at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:473)
       at javax.crypto.Cipher.doFinal(Cipher.java:1502)
       at com.mtramin.rxfingerprint.FingerprintEncryptionObservable.onAuthenticationSucceeded(Unknown Source:112)
       at com.mtramin.rxfingerprint.FingerprintObservable$2.onAuthenticationSucceeded(Unknown Source:114)
       at android.hardware.fingerprint.FingerprintManager$MyHandler.sendAuthenticatedSucceeded(FingerprintManager.java:882)
       at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage(FingerprintManager.java:834)
       at android.os.Handler.dispatchMessage(Handler.java:111)
       at android.os.Looper.loop(Looper.java:207)
       at android.app.ActivityThread.main(ActivityThread.java:5765)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)

Exception when restoring app

Hi,

I am facing an issue when an user restore my app with TitaniumBackup or synchronize it from another phone (example: samsung). Here is the exception:

java.security.InvalidKeyException: Key for algorithm null not suitable for symmetric enryption.
    at org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineInit(BaseBlockCipher.java:496)
    at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:2973)
    at javax.crypto.Cipher.tryCombinations(Cipher.java:2884)
    at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider(Cipher.java:2789)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:956)
    at javax.crypto.Cipher.init(Cipher.java:1329)
    at javax.crypto.Cipher.init(Cipher.java:1267)
    at com.mtramin.rxfingerprint.AesCipherProvider.getCipherForDecryption(AesCipherProvider.java:87)
    at com.mtramin.rxfingerprint.AesDecryptionObservable.initCryptoObject(AesDecryptionObservable.java:83)
    at com.mtramin.rxfingerprint.FingerprintObservable.subscribe(FingerprintObservable.java:70)
    ...

The error comes from this portion of code in file AesCipherProvider.java.

	/**
	 * @param iv initialization vector used during encryption
	 * @return Initialized cipher for decryption operations in RxFingerprint
	 */
	Cipher getCipherForDecryption(byte[] iv) throws CertificateException, NoSuchAlgorithmException, IOException, InvalidKeyException, UnrecoverableKeyException, KeyStoreException, InvalidAlgorithmParameterException, NoSuchPaddingException {
		Cipher cipher = createCipher();
		SecretKey key = getKey(keyName);
		cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); // This line
		return cipher;
	}

Do you think it would be ok to detect this behavior and instead throw an InvalidatedKeyException with the removal of the key?

Thanks,

RSA Decryption throwing exception?

My production code is crashing and the crash log from the play store ANRs & Crashes give me following log. What could be causing this?

io.reactivex.exceptions.CompositeException: 
  at io.reactivex.internal.observers.LambdaObserver.onError (LambdaObserver.java:77)
  at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onError (ObservableSubscribeOn.java:63)
  at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.tryOnError (ObservableCreate.java:85)
  at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onError (ObservableCreate.java:73)
  at com.mtramin.rxfingerprint.RsaDecryptionObservable.initCryptoObject (RsaDecryptionObservable.java:79)
  at com.mtramin.rxfingerprint.FingerprintObservable.subscribe (FingerprintObservable.java:70)
  at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual (ObservableCreate.java:40)
  at io.reactivex.Observable.subscribe (Observable.java:10838)
  at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run (ObservableSubscribeOn.java:96)
  at io.reactivex.Scheduler$DisposeTask.run (Scheduler.java:452)
  at io.reactivex.internal.schedulers.ScheduledRunnable.run (ScheduledRunnable.java:61)
  at io.reactivex.internal.schedulers.ScheduledRunnable.call (ScheduledRunnable.java:52)
  at java.util.concurrent.FutureTask.run (FutureTask.java:266)
  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java:301)
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1162)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:636)
  at java.lang.Thread.run (Thread.java:764)

More specific error message in RxFingerprint.decrypt

Hey there,

Having some issues with RxFingerprint.decrypt here: In very rare cases this crashes for some of our users (mostly on Samsung S5 and S6) with the error message "Invalid input given for decryption operation. Make sure you provide a string that was previously encrypted by RxFingerprint.".

Can you extend this error message with something telling us if the encrypted string was empty or if it was missing the separator? Might help tracking down the issue.

The error message comes from CryptoData:53 and could be something like this:
"Invalid input given for decryption operation. Make sure you provide a string that was previously encrypted by RxFingerprint. encryptedData.length: 0, contains separator: false”

Thanks!

Memory Leak

Getting leak of 4.7KB using this library.Added the screenshot also for better clarity.This is the snippet that I have used in my project which gets the leak which is determined by the Leak Canary tool.

  private void fingerprintAuthentication() {
    if (RxFingerprint.isAvailable(getAppContextFromView())) {
        mDisposable = RxFingerprint.authenticate(getAppContextFromView())
                .subscribeOn(Schedulers.io())
                .subscribe(fingerprintAuthenticationResult -> {
                    switch (fingerprintAuthenticationResult.getResult()) {
                        case FAILED:
                            Toast.makeText(getAppContextFromView(),
                                    R.string.error_finger_print_not_valid,
                                    Toast.LENGTH_SHORT).show();
                            if (mFingerPrintTouchCallBack != null) {
                                mFingerPrintTouchCallBack.onAuthenticationFailed();
                            }

                            break;
                        case HELP:
                            Toast.makeText(getAppContextFromView(),
                                    fingerprintAuthenticationResult.getMessage(),
                                    Toast.LENGTH_SHORT).show();
                            break;
                        case AUTHENTICATED:
                            if (mFingerPrintTouchCallBack != null) {
                                mFingerPrintTouchCallBack.onAuthenticationSuccess();
                                mConfirmPinPresenter.pinUpdated();
                            }
                            break;
                    }
                }, throwable -> {
                    if (throwable instanceof FingerprintAuthenticationException) {
                        if (throwable.getMessage() != null && throwable.getMessage()
                                .contains(
                                        TOO_MANY_ATTEMPT_STR)) {
                            Toast.makeText(getAppContextFromView(),
                                    throwable.getMessage(),
                                    Toast.LENGTH_SHORT).show();
                            mConfirmPinPresenter.logout();
                        }
                    }
                });
    }
}

screenshot_20171218-142955

Add sign and verify functions for RSA

Hi,

After successful fingerprint authentication I need to sign data with RSA and then send it to the server for verifying.

I think that those functions could be interesting to more users. Please consider adding them.

ClassCastException while AES encryption

I'm trying to encrypt data with AES and getting ClassCast. Example:
RxFingerprint.encrypt(EncryptionMethod.AES, getActivity(),mKeyName, data)

java.lang.ClassCastException: android.security.keystore.AndroidKeyStoreRSAPrivateKey cannot be cast to javax.crypto.SecretKey
at com.mtramin.rxfingerprint.AesCipherProvider.getKey(AesCipherProvider.java:60)
at com.mtramin.rxfingerprint.AesCipherProvider.findOrCreateKey(AesCipherProvider.java:54)
at com.mtramin.rxfingerprint.AesCipherProvider.cipherForEncryption(AesCipherProvider.java:75)
at com.mtramin.rxfingerprint.CipherProvider.getCipherForEncryption(CipherProvider.java:84)
at com.mtramin.rxfingerprint.AesEncryptionObservable.initCryptoObject(AesEncryptionObservable.java:83)
at com.mtramin.rxfingerprint.FingerprintObservable.subscribe(FingerprintObservable.java:70)
at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.java:40)
at io.reactivex.Observable.subscribe(Observable.java:11194)
at io.reactivex.Observable.subscribe(Observable.java:11180)
at io.reactivex.Observable.subscribe(Observable.java:11109)
at com.org.android.monitor.test.LoginFragment.storeAndLogin(LoginFragment.java:140)
at com.org.android.monitor.test.LoginFragment.access$000(LoginFragment.java:34)
at com.org.android.monitor.test.LoginFragment$1.lambda$onResponse$2$LoginFragment$1(LoginFragment.java:203)
at com.org.android.monitor.test.LoginFragment$1$$Lambda$1.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:754)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:163)
at android.app.ActivityThread.main(ActivityThread.java:6337)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:880)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:770)

Consider using AutoValue for all result classes

I would like to be able to log the result objects. Implementing toString for each object may become cumbersome to maintain in the future, so AutoValue seams like a good fit here.
For FingerprintDecyptionResult auto-value-redacted can be used to avoid leacage of sensetive data in logs.

NullPointerException on AesDecryptionObservable.java:95

Occuring on these devices:
Motorola Moto G Plus (5th Gen), Android 7.0,
Motorola Moto E (4), Android 7.1,
Sony Xperia X (F5121), Android 8.0,
Motorola Moto G (5S), Android 7.1

I don't have on of these to test on. May someone who have one can check it.

java.lang.NullPointerException: at com.mtramin.rxfingerprint.AesDecryptionObservable.onAuthenticationSucceeded (AesDecryptionObservable.java:95) at com.mtramin.rxfingerprint.FingerprintObservable$2.onAuthenticationSucceeded (FingerprintObservable.java:105) at android.hardware.fingerprint.FingerprintManager$MyHandler.sendAuthenticatedSucceeded (FingerprintManager.java:894) at android.hardware.fingerprint.FingerprintManager$MyHandler.handleMessage (FingerprintManager.java:842) at android.os.Handler.dispatchMessage (Handler.java:110) at android.os.Looper.loop (Looper.java:203) at android.app.ActivityThread.main (ActivityThread.java:6339) at java.lang.reflect.Method.invoke (Method.java) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1084) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:945)

Consider using FingerprintManager instead of FingerprintManagerCompat

Some devices that have a fingerprint sensor are not specifying the system feature FEATURE_FINGERPRINT correctly. The support library is explicitly checking for the system feature.

This leads devices which actually have a fingerprint sensor to report false for RxFingerprint.isHardwareDetected check.

Using the FingerprintManager directly and not doing this check should allow the offending devices to be used with the library. However it is not guaranteed that all devices which do not specify the FEATURE_FINGERPRINT feature even implement the Fingerprint API classes correctly.

AOSP issue: https://code.google.com/p/android/issues/detail?id=231939

Too many tries should be a recoverable error

com.mtramin.rxfingerprint.data.FingerprintAuthenticationException: Too many attempts. Try again later.

in this case onError is called which will end the stream, however, this is a recoverable error, all you need to do it try again later...

Expose errMsgId to subscribers

If the fingerprint authentication fails with an error like FINGERPRINT_ERROR_LOCKOUT, the UI should display an error for a longer period of time than if the error is FINGERPRINT_ACQUIRED_TOO_FAST for example. There is currently no way to know what the specific error condition of the reader is. The error id should be passed along inside FingerprintAuthenticationException

launchFingerprintEnrollment without hasEnrolledFingerprints

Hi,

I am using the release 3.0.0-RC-1 and I have a question.
You just deprecated some methods including "hasEnrolledFingerprints". If I don't use "hasEnrolledFingerprints", how can I know if I need to use the method "launchFingerprintEnrollment" on Android P?

I tried to test "rxFingerprint.encrypt(KEY_NAME, stringToEncrypt)"... but the exception returned is of no use.

java.security.InvalidAlgorithmParameterException: java.lang.IllegalStateException: At least one fingerprint must be enrolled to create keys requiring user authentication for every use
at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi.engineInit(AndroidKeyStoreKeyGeneratorSpi.java:254)
at android.security.keystore.AndroidKeyStoreKeyGeneratorSpi$AES.engineInit(AndroidKeyStoreKeyGeneratorSpi.java:54)
at javax.crypto.KeyGenerator.init(KeyGenerator.java:519)
at javax.crypto.KeyGenerator.init(KeyGenerator.java:502)
at com.mtramin.rxfingerprint.AesCipherProvider.createKey(AesCipherProvider.java:62)
at com.mtramin.rxfingerprint.AesCipherProvider.findOrCreateKey(AesCipherProvider.java:52)
at com.mtramin.rxfingerprint.AesCipherProvider.cipherForEncryption(AesCipherProvider.java:71)
at com.mtramin.rxfingerprint.CipherProvider.getCipherForEncryption(CipherProvider.java:89)
at com.mtramin.rxfingerprint.FingerprintDialogAesEncryptionObservable.initCryptoObject(FingerprintDialogAesEncryptionObservable.java:89)
at com.mtramin.rxfingerprint.FingerprintDialogObservable.subscribe(FingerprintDialogObservable.java:70)

I was surprised to see that in your code, the method "isAvailable" does not checks for enrollments for Android P. Is it normal?

Thanks,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.