Kunzisoft / KeePassDX

Lightweight vault and password manager for Android, KeePassDX allows editing encrypted data in a single file in KeePass format and fill in the forms in a secure way.
https://www.keepassdx.com/
GNU General Public License v3.0
4.58k stars 270 forks source link

Support yubikey challenge response #8

Closed piratenpanda closed 1 year ago

piratenpanda commented 6 years ago

Would be nice if the app would support challenge response via the yubichallenge app

uduerholz commented 2 years ago

Happy to see you are working on this. In my opinion the security benefit of generating a fresh seed every time the file is saved is very small and doesn't justify the effort in this case. BTW: I tested my implementation only via NFC.

J-Jamet commented 2 years ago

I think on the contrary that the seed should be randomize, otherwise there is no point in having it if it always stays the same. Afterwards, there is nothing to prevent from making it a parameter and asking the user not to randomize it at each save. After I agree with you, it's a lot of work for just that but I prefer to respect the workflow, because otherwise it will be more complicated when it comes to managing FIDO2.

(Whether by NFC or OTG, it doesn't change anything, the logic of the answer is encapsulated externally.)

uduerholz commented 2 years ago

Yes, of course you need a random seed - but only once, when the database is created. What is the benefit, if you replace a random value with another random value?

J-Jamet commented 2 years ago

If a lazy user only uses the Yubikey, uploads it to a cloud and his database is compromised, he will change the passwords of his entries and resave his database with his Yubikey (with the same seed) thinking it is ok.

But if a hacker had previously recovered the generated key, he will be able to reuse it later to unlock the database with the new data even without having a Yubikey. I use a plug on emulator that always send the same unlock key, it reproduces this behavior.

I agree, it's a pain in the ass to use, that's why I was thinking of a parameter to prevent randomizing the seed just temporarily if you make regular saves when you fill a database.

J-Jamet commented 2 years ago

Currently the functionality works well but I would like to improve the driver concept (for example : by implementing a hardware key emulator in a new app) and not be dependent on Ykdroid. The problem, currently, is that the calling intent is "net.pp3345.ykdroid.intent.action.CHALLENGE_RESPONSE", which is very coupled to the ykdroid app and not generic enough. I will propose this intent "android.yubikey.intent.action.CHALLENGE_RESPONSE" to be implemented so that you have a choice between driver apps. Tell me what you think about it.

uduerholz commented 2 years ago

I dont' really see your point here. If KeepassDX doesn't get the response from the Yubikey, then some other app must do so. So there will always be a dependency on some other app. I think that's okay. If you change the Intent, ykdroid cannot be used anymore.

J-Jamet commented 2 years ago

If KeepassDX doesn't get the response from the Yubikey, then some other app must do so

This is precisely the problem. If I (or someone else, whatever) create another application that delivers an answer from a Yubikey challenge then a choice will have to be made previously in the code about which application to use (ykDroid or another, so does not leave the choice to the user). If we make a generic intent, it will be up to the user to make that choice because several applications will be compatible. It is simply a matter of convention.

If you change the Intent, ykDroid cannot be used anymore.

That's why I would like to make a generic intent and I opened a ticket. If another application is created to challenge Yubikey (for example an official Yubico application), it will clearly not use an intent that contains a package name from another application that does the same thing. ;)

Also, I wonder if we should not make a generic intent for the challenge response of any hardware key, with different parameters. This would allow to use the same intent for a FIDO2 key. We should contact other app creators who would be interested in creating conventions.

uduerholz commented 2 years ago

Okay, I see. Don't know if there will be other apps with the same functionality as ykdroid. But can't hurt to generalize the intent name.

J-Jamet commented 2 years ago

OK, as ykDroid has not merged the changes yet. I created a new application based on the driver code which will have improvements (virtual Yubikey key with recovery key use in case of loss) and will also integrate the drivers for FIDO2. There is still a lot of work to do and Google has not yet validated the first upload of the beta but it will allow to test in good conditions. I will probably need help to implement the new features.

J-Jamet commented 2 years ago

Here is an overview of unlocking a database with a Yubikey in USB OTG and the new driver application :

cb2d23

pmorange commented 2 years ago

Looks real good @J-Jamet

For me, an important aspect of the implementation would be how often the key would need to be used for quick unlock or that kind of feature. As I said in a comment in another issue, I'm currently using KeePassDX's competitor and although I have "Quick Unlock" activated, the app forces me to use the Yubikey way too often (and each time enter my very long unlock password too). That's why I'm looking for alternatives. I don't know if this is really possible, but once unlocked with Yubikey the ideal would be to be able to unlock the DB with fingerprint only until phone is restarted : in that case the Yubikey would be necessary to unlock DB again. Some will prefer stronger security but I like to be able to unlock DB on my phone without needing to always have the Yubikey near me...

Thanks for the good work.

J-Jamet commented 2 years ago

For me, an important aspect of the implementation would be how often the key would need to be used for quick unlock or that kind of feature.

Pretty simple to answer : There is no quick unlock and the functionality will not be integrated for the reasons that are in the wiki. https://github.com/Kunzisoft/KeePassDX/wiki/Advanced-Unlocking#why-not-quick-unlock

I don't know if this is really possible, but once unlocked with Yubikey the ideal would be to be able to unlock the DB with fingerprint only until phone is restarted : in that case the Yubikey would be necessary to unlock DB again.

This functionality is under study, for the moment only the password can be associated with a fingerprint. I plan to extend advanced unlock to key files and hardware keys but I can't say without having the technical constraints after testing. Linked to https://github.com/Kunzisoft/KeePassDX/issues/427 https://github.com/Kunzisoft/KeePassDX/issues/1315

Some will prefer stronger security but I like to be able to unlock DB on my phone without needing to always have the Yubikey near me...

In this case, there is a limited interest in using it. The purpose of a challenge response is to generate from new keys each time a different response understandable by the challenge emitter. In other words, it is meant to certify a physical presence of the user.

If you want to store the final decryption key in the client system for ease of use, there is no need to have a physical authentication system for the user since you have stored his authentication system locally. It can be stored temporarily, but you have to keep in mind that this goes against the basic principle of the feature.

Another point can be frightening: at each save, it is necessary to reuse the Yubikey to generate a new key. But for me it's normal because otherwise there would be no interest to use this key. It's like every time, people want security AND ease of use but it's always a choice to make.

jivarson commented 2 years ago

Here is an overview of unlocking a database with a Yubikey in USB OTG and the new driver application :

Is this NFC compatible as well?

rugk commented 2 years ago

Note for NFC compatibility, you may have a look at https://github.com/microg/GmsCore/issues/849, as there as far as I see such a thing is also currently being implemented.

J-Jamet commented 2 years ago

Is this NFC compatible as well?

Yes, I need to do more tests but it should work. Thx @rugk for the link.

J-Jamet commented 2 years ago

I just uploaded the beta of version 3.5.0. Those who are subscribed to the beta on the Play Store will be able to use their Yubikey. But Google doesn't want to validate the Key Driver application so it's only downloadable in debug version for the moment.

jivarson commented 2 years ago

I just uploaded the beta of version 3.5.0. Those who are subscribed to the beta on the Play Store will be able to use their Yubikey. But Google doesn't want to validate the Key Driver application so it's only downloadable in debug version for the moment.

It's works, awesome!! Just created a kdbx with the 3.5.0 and your Key Driver from Play store. I'll make a copy of my main vault and use this as a daily driver to report if anything breaks.

exstntlmsnthrp commented 2 years ago

I just uploaded the beta of version 3.5.0. Those who are subscribed to the beta on the Play Store will be able to use their Yubikey. But Google doesn't want to validate the Key Driver application so it's only downloadable in debug version for the moment.

Not all of us use the Play Store. When will this be available to the rest of us? And where does one find the Key Driver app? Maybe I looked in the wrong place, but didn't find it. Cheers.

J-Jamet commented 2 years ago

https://github.com/Kunzisoft/KeePassDX/releases/tag/3.5.0beta01 https://gitlab.com/kunzisoft/android-hardware-key-driver

https://github.com/Kunzisoft/KeePassDX/issues/1080

agates commented 2 years ago

I just uploaded the beta of version 3.5.0. Those who are subscribed to the beta on the Play Store will be able to use their Yubikey. But Google doesn't want to validate the Key Driver application so it's only downloadable in debug version for the moment.

I've got the Key Driver installed from Google Play. It seems to either be crashing or not loading correctly when KeePassDX is waiting for the challenge response.

Happy to open an issue in Gitlab, just let me know what information I need or if there's a way to provide you debug logs.

Also, thank you for your work! I've purchased "KeePro" to support you.

macearl commented 2 years ago

For me it also crashes after attaching the yubikey/while waiting for the challenge response.

Not sure if you want additional information here or over on gitlab in the hardware key driver repo.

Android Version: LineageOS for microG 19.1 Device: Xiaomi Pocophone F1 Stacktrace:

FATAL EXCEPTION: main
Process: com.kunzisoft.hardware.key, PID: 21629
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.hardware.usb.action.USB_DEVICE_ATTACHED flg=0x11000010 (has extras) } in com.kunzisoft.hardware.key.ConnectionManager@d846016
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1689)
    at android.app.LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0.run(Unknown Source:2)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7870)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.IllegalArgumentException: com.kunzisoft.hardware.key: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
    at android.app.PendingIntent.checkFlags(PendingIntent.java:375)
    at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:645)
    at android.app.PendingIntent.getBroadcast(PendingIntent.java:632)
    at com.kunzisoft.hardware.key.ConnectionManager.requestPermission(ConnectionManager.java:242)
    at com.kunzisoft.hardware.key.ConnectionManager.onReceive(ConnectionManager.java:182)
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1679)
    ... 9 more
J-Jamet commented 2 years ago

Thanks for the logs, I will try to solve the problem quickly in the Driver Key App.

nagromc commented 2 years ago

I just installed Key Driver alongside KeePassDX, and KeePro Unlocker, and tried to unlock my password DB. Unfortunately, I cannot open it.

Here is what I’ve done:

If you require a stacktrace, please tell me how to get it.

KeePassDX v3.5.0 Beta01 KeePro Unlocker v4.2 Key Driver v0.1.2 Yubikey NEO with challenge-response configured on slot 2

jivarson commented 2 years ago

One thing that isn't possible either with this Key Driver nor YkDroid is to use Yubikey on a Chromebook with USB-A (without NFC). I guess this isn't something easy to fix in Key Driver?

J-Jamet commented 2 years ago

@macearl It seems to be a problem with pending intent flags, I will update the call in version 0.1.3 to avoid the crash on your device.

@nagromc It seems to be a problem with the detection of the driver application during the query in the database opening thread. It happens if the intent request in the thread is not received, in this case you have to press the "Cancel" button and start the database opening again. The goal is to have access to the hardware key detection application in the database opening workflow, which is put on hold until the response is received.

@jivarson

I guess this isn't something easy to fix in Key Driver?

I don't have a chomebook, so I can't test. Maybe version 0.1.3 will solve the problem. If not, someone with the hardware and knowledge will have to look into the problem, but theoretically it should work, but there may be weird incompatibilities.

super9mega commented 2 years ago

following your gitlab pipelines, installing the debug app, I'm able to get it to not crash like before but now I'm getting this crash after I scan the key

09-15 15:07:58.987  1956 20940 W ActivityTaskManager: startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: Intent { cmp=com.kunzisoft.hardware.key/.ChallengeResponseActivity }
09-15 15:07:58.993 16320 16320 D AndroidRuntime: Shutting down VM
09-15 15:07:58.995 16320 16320 E AndroidRuntime: FATAL EXCEPTION: main
09-15 15:07:58.995 16320 16320 E AndroidRuntime: Process: com.kunzisoft.hardware.key, PID: 16320
09-15 15:07:58.995 16320 16320 E AndroidRuntime: java.lang.AssertionError
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at com.kunzisoft.hardware.key.ConnectionManager.onReceive(ConnectionManager.java:186)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at com.kunzisoft.hardware.key.ChallengeResponseActivity.onNewIntent(ChallengeResponseActivity.kt:166)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.Activity.performNewIntent(Activity.java:8306)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.Instrumentation.callActivityOnNewIntent(Instrumentation.java:1490)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.Instrumentation.callActivityOnNewIntent(Instrumentation.java:1503)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.ActivityThread.deliverNewIntents(ActivityThread.java:3853)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.ActivityThread.handleNewIntent(ActivityThread.java:3860)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.servertransaction.NewIntentItem.execute(NewIntentItem.java:56)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:106)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.os.Looper.loopOnce(Looper.java:201)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:288)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:7894)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:550)
09-15 15:07:58.995 16320 16320 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
09-15 15:07:58.996  1311  1311 D vendor.qti.vibrator: QTI Vibrator on for 200 ms with a gain of 0x80
09-15 15:07:58.999  1956  2038 W ActivityTaskManager:   Force finishing activity com.kunzisoft.hardware.key/.ChallengeResponseActivity
09-15 15:07:59.012 16320 16320 I Process : Sending signal. PID: 16320 SIG: 9
09-15 15:07:59.047  1956  4307 I WindowManager: WIN DEATH: Window{df46663 u0 com.kunzisoft.hardware.key/com.kunzisoft.hardware.key.ChallengeResponseActivity}
09-15 15:07:59.047  1956  4307 W InputManager-JNI: Input channel object 'df46663 com.kunzisoft.hardware.key/com.kunzisoft.hardware.key.ChallengeResponseActivity (client)' was disposed without first being removed with the input manager!
09-15 15:07:59.048  1956  2038 I ActivityManager: Process com.kunzisoft.hardware.key (pid 16320) has died: fg  TOP
09-15 15:07:59.048  1078  1078 I Zygote  : Process 16320 exited due to signal 9 (Killed)
09-15 15:07:59.071 12436 12436 E HardwareKeyResponseHelper: Response from challenge error
09-15 15:07:59.095  1956  2276 W WindowManager: Failed to deliver inset state change to w=Window{df46663 u0 com.kunzisoft.hardware.key/com.kunzisoft.hardware.key.ChallengeResponseActivity EXITING}
09-15 15:07:59.095  1956  2276 W WindowManager: android.os.DeadObjectException
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.os.BinderProxy.transactNative(Native Method)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.os.BinderProxy.transact(BinderProxy.java:584)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.view.IWindow$Stub$Proxy.insetsControlChanged(IWindow.java:473)
09-15 15:07:59.095  1956  2276 W WindowManager:         at com.android.server.wm.WindowState.notifyInsetsControlChanged(WindowState.java:3994)
09-15 15:07:59.095  1956  2276 W WindowManager:         at com.android.server.wm.InsetsStateController.lambda$notifyPendingInsetsControlChanged$5$com-android-server-wm-InsetsStateController(InsetsStateController.java:348)
09-15 15:07:59.095  1956  2276 W WindowManager:         at com.android.server.wm.InsetsStateController$$ExternalSyntheticLambda4.run(Unknown Source:2)
09-15 15:07:59.095  1956  2276 W WindowManager:         at com.android.server.wm.WindowAnimator.executeAfterPrepareSurfacesRunnables(WindowAnimator.java:345)
09-15 15:07:59.095  1956  2276 W WindowManager:         at com.android.server.wm.WindowAnimator.animate(WindowAnimator.java:226)
09-15 15:07:59.095  1956  2276 W WindowManager:         at com.android.server.wm.WindowAnimator.lambda$new$1$com-android-server-wm-WindowAnimator(WindowAnimator.java:106)
09-15 15:07:59.095  1956  2276 W WindowManager:         at com.android.server.wm.WindowAnimator$$ExternalSyntheticLambda1.doFrame(Unknown Source:2)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1229)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.view.Choreographer.doCallbacks(Choreographer.java:899)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.view.Choreographer.doFrame(Choreographer.java:827)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.os.Handler.handleCallback(Handler.java:942)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.os.Handler.dispatchMessage(Handler.java:99)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.os.Looper.loopOnce(Looper.java:201)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.os.Looper.loop(Looper.java:288)
09-15 15:07:59.095  1956  2276 W WindowManager:         at android.os.HandlerThread.run(HandlerThread.java:67)
09-15 15:07:59.095  1956  2276 W WindowManager:         at com.android.server.ServiceThread.run(ServiceThread.java:44)
09-15 15:07:59.112  1956  2276 W WindowManager: Exception thrown during dispatchAppVisibility Window{df46663 u0 com.kunzisoft.hardware.key/com.kunzisoft.hardware.key.ChallengeResponseActivity EXITING}
09-15 15:07:59.112  1956  2276 W WindowManager: android.os.DeadObjectException
09-15 15:07:59.112  1956  2276 W WindowManager:         at android.os.BinderProxy.transactNative(Native Method)
09-15 15:07:59.112  1956  2276 W WindowManager:         at android.os.BinderProxy.transact(BinderProxy.java:584)
09-15 15:07:59.112  1956  2276 W WindowManager:         at android.view.IWindow$Stub$Proxy.dispatchAppVisibility(IWindow.java:536)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.WindowState.sendAppVisibilityToClients(WindowState.java:3489)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.WindowContainer.sendAppVisibilityToClients(WindowContainer.java:1199)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.WindowToken.setClientVisible(WindowToken.java:398)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.ActivityRecord.setClientVisible(ActivityRecord.java:6564)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.ActivityRecord.onAnimationFinished(ActivityRecord.java:7351)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.ActivityRecord.postApplyAnimation(ActivityRecord.java:5263)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.ActivityRecord.commitVisibility(ActivityRecord.java:5235)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.ActivityRecord.commitVisibility(ActivityRecord.java:5239)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.AppTransitionController.handleClosingApps(AppTransitionController.java:1098)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.AppTransitionController.handleAppTransitionReady(AppTransitionController.java:286)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.RootWindowContainer.checkAppTransitionReady(RootWindowContainer.java:975)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:842)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:784)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.wm.WindowSurfacePlacer$Traverser.run(WindowSurfacePlacer.java:57)
09-15 15:07:59.112  1956  2276 W WindowManager:         at android.os.Handler.handleCallback(Handler.java:942)
09-15 15:07:59.112  1956  2276 W WindowManager:         at android.os.Handler.dispatchMessage(Handler.java:99)
09-15 15:07:59.112  1956  2276 W WindowManager:         at android.os.Looper.loopOnce(Looper.java:201)
09-15 15:07:59.112  1956  2276 W WindowManager:         at android.os.Looper.loop(Looper.java:288)
09-15 15:07:59.112  1956  2276 W WindowManager:         at android.os.HandlerThread.run(HandlerThread.java:67)
09-15 15:07:59.112  1956  2276 W WindowManager:         at com.android.server.ServiceThread.run(ServiceThread.java:44)
09-15 15:07:59.148 12436 12463 E com.kunzisoft.keepass.database.element.Database: Unable to load the database
09-15 15:07:59.148 12436 12463 E ActionRunnable: success=false
09-15 15:07:59.148 12436 12463 E ActionRunnable: java.util.concurrent.CancellationException: Unable to get the response from the challenge.
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.kunzisoft.keepass.services.DatabaseTaskNotificationService.cancelChallengeResponse(DatabaseTaskNotificationService.kt:264)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.kunzisoft.keepass.services.DatabaseTaskNotificationService.access$cancelChallengeResponse(DatabaseTaskNotificationService.kt:62)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.kunzisoft.keepass.services.DatabaseTaskNotificationService$respondToChallenge$1.invokeSuspend(DatabaseTaskNotificationService.kt:273)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at android.os.Handler.handleCallback(Handler.java:942)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at android.os.Handler.dispatchMessage(Handler.java:99)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at android.os.Looper.loopOnce(Looper.java:201)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at android.os.Looper.loop(Looper.java:288)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at android.app.ActivityThread.main(ActivityThread.java:7894)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at java.lang.reflect.Method.invoke(Native Method)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:550)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
09-15 15:07:59.148 12436 12463 E ActionRunnable: com.kunzisoft.keepass.database.exception.DatabaseInputException
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.kunzisoft.keepass.database.element.Database.loadData(Database.kt:624)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.kunzisoft.keepass.database.action.LoadDatabaseRunnable.onActionRun(LoadDatabaseRunnable.kt:56)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.kunzisoft.keepass.tasks.ActionRunnable.run(ActionRunnable.kt:36)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at com.kunzisoft.keepass.services.DatabaseTaskNotificationService$executeAction$2$1$asyncResult$1.invokeSuspend(DatabaseTaskNotificationService.kt:587)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
09-15 15:07:59.148 12436 12463 E ActionRunnable:        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
09-15 15:07:59.166  1956 20940 D CoreBackPreview: Window{d0c6249 u0 com.kunzisoft.keepass.free/com.kunzisoft.keepass.activities.MainCredentialActivity}: Setting back callback null
macearl commented 2 years ago

Thanks for the quick response. With 0.13 I can occasionally finish the challenge response, sometime however it still crashes with another intent related(?) problem:

FATAL EXCEPTION: main
Process: com.kunzisoft.hardware.key, PID: 9848
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.yubikey.intent.action.USB_PERMISSION_REQUEST flg=0x10 } in com.kunzisoft.hardware.key.ConnectionManager@768bda5
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1689)
    at android.app.LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0.run(Unknown Source:2)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7870)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.hardware.usb.UsbDevice.getVendorId()' on a null object reference
    at com.kunzisoft.hardware.yubikey.challenge.UsbYubiKey$Type.lookupDeviceType(UsbYubiKey.java:121)
    at com.kunzisoft.hardware.yubikey.challenge.UsbYubiKey$Type.isDeviceKnown(UsbYubiKey.java:131)
    at com.kunzisoft.hardware.key.ConnectionManager.requestPermission(ConnectionManager.java:240)
    at com.kunzisoft.hardware.key.ConnectionManager.onReceive(ConnectionManager.java:193)
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1679)
    ... 9 more

what I forgot earlier: I also have ykdroid and yubico Authenticator installed. Yubico authenticator also auto starts every time I plug in my yubikey (so far I have not found a way to disable this) and so maybe messes up the unlock flow (keepassdx gets started, I click unlock key driver starts, I plug in my yubikey, yubico authenticator auto starts, I click back to key driver and try to complete the unlock)

I'll see if I can find another android device to test on without those apps installed, if no one else experiences the same problem.

J-Jamet commented 2 years ago

Thank you @super9mega and @macearl , your logs are very useful. There are assertions to remove and null checks to manage, I wanted to keep the java code for simplicity but it makes more sense to migrate it to Kotlin, I will do that when I have time. The problem is that I don't have a recent device with Android 12 or 13 to test in real conditions so it's a bit hard to debug the driver.

nagromc commented 2 years ago

@nagromc It seems to be a problem with the detection of the driver application during the query in the database opening thread. It happens if the intent request in the thread is not received, in this case you have to press the "Cancel" button and start the database opening again. The goal is to have access to the hardware key detection application in the database opening workflow, which is put on hold until the response is received.

I’ve tried multiple times, but I hear the same "failing" chord every time.

With KP2A, ykDroid prompt is displayed on top of KP2A to ask the user to swipe his Yubikey. When I try to swipe the Yubikey out of this prompt (say, from the desktop, i.e. with no app launched), I hear the "failing" chord.

I noted that if I install the Pass Pass Easy Card app (an app to check how many dematerialized public transport ticket we have), when I try to unlock my KDBX, I can hear the usual sound when it succeeds to read the Yubikey. I suspect the Pass Pass Easy Card app to read the NFC chip, instead of KeePassDX.

J-Jamet commented 2 years ago

@nagromc The Key Driver app works the same way as ykDroid and is displayed above KeePassDX -> https://github.com/Kunzisoft/KeePassDX/issues/8#issuecomment-1211858310 (Key Driver is only in full screen to avoid flickering.) Try disabling the Easy Card Pass application to see if that is where the problem lies.

nagromc commented 2 years ago

@J-Jamet I’ve already tried to uninstall the Pass Pass Easy Card app, but the failing chord rings. It is like the Key Driver just ignores the Yubikey. Would a stacktrace help? If so, could you give me a link explaining how to get it?

J-Jamet commented 2 years ago

I would like to be sure that the problem comes from Key Driver, KeePassDX 4.5.0beta should work with this modified ykDroid which allows the management of the new intent. Can you confirm it? yKDroid_2.1.2_mod.zip

(Logs : https://www.xda-developers.com/how-to-take-logs-android/)

nagromc commented 2 years ago

It works with ykDroid v1.2.1_mod.

Here is a capture of KeePassDX with ykDroid 1.2.1_mod and with Key Driver: https://drive.proton.me/urls/JEVJA27TBM#eeWqLkhfiMcE

Please note I have now a different behaviour when ykDroid v1.2.1_mod is installed in lieu of the regular version: when trying to swipe with the Yubikey, I have now an error message.

This stracktrace may help (thanks for the link):

09-16 10:19:18.299 29465 29465 E AndroidRuntime: FATAL EXCEPTION: main
09-16 10:19:18.299 29465 29465 E AndroidRuntime: Process: com.kunzisoft.hardware.key, PID: 29465
09-16 10:19:18.299 29465 29465 E AndroidRuntime: java.lang.RuntimeException: Unable to resume activity {com.kunzisoft.hardware.key/com.kunzisoft.hardware.key.ChallengeResponseActivity}: java.lang.IllegalArgumentException: com.kunzisoft.hardware.key: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
09-16 10:19:18.299 29465 29465 E AndroidRuntime: Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4935)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4974)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:60)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2345)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:106)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.os.Looper.loopOnce(Looper.java:233)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:344)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:8212)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1034)
09-16 10:19:18.299 29465 29465 E AndroidRuntime: Caused by: java.lang.IllegalArgumentException: com.kunzisoft.hardware.key: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
09-16 10:19:18.299 29465 29465 E AndroidRuntime: Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.PendingIntent.checkFlags(PendingIntent.java:378)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.PendingIntent.getActivityAsUser(PendingIntent.java:461)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.PendingIntent.getActivity(PendingIntent.java:447)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.PendingIntent.getActivity(PendingIntent.java:411)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at com.kunzisoft.hardware.key.ConnectionManager.initNFCConnection(ConnectionManager.java:134)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at com.kunzisoft.hardware.key.ConnectionManager.onActivityResumed(ConnectionManager.java:108)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.Application.dispatchActivityResumed(Application.java:430)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.Activity.dispatchActivityResumed(Activity.java:1400)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.Activity.onResume(Activity.java:1966)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at androidx.fragment.app.FragmentActivity.onResume(FragmentActivity.java:310)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1491)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.Activity.performResume(Activity.java:8280)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4925)
09-16 10:19:18.299 29465 29465 E AndroidRuntime:    ... 13 more
J-Jamet commented 1 year ago

I released version 0.1.4 of Key Driver, version 3.5.0Beta02 should be validated by Google in beta soon. Normally there should be no more crashes. Don't hesitate to give feedback. ;)

super9mega commented 1 year ago

So! Seems to have solved the crashing (not by my computer so I can't get a log) but now it just makes the sound and never moves on towards opening the database. Also, it's not the connect sound, it's the same sound it makes when you do it without any app open. I'll post my logs when I'm next to a computer (pixel 6 pro, Android 13)

wandering-tales commented 1 year ago

I still suffer crashes after upgrading both Key Driver 0.1.4 and KeePassDX to 3.5.0beta02.

As soon as I plug my YubiKey 5C, my Yubico Authenticator app is opened. Then if I switch back to the KeyPassDX app, I am prompted to allow the Key Driver to use the YubiKey, I press OK and the app crashes. Here's some screenshot:

Screenshot_20221016-230152.png

Screenshot_20221016-230230.png

I have also sent a crash report via Android.

J-Jamet commented 1 year ago

It's strange, the crash reports are only for the 0.1.3 versions of Key Driver but I don't have any crash report for the 0.1.4 version.

wandering-tales commented 1 year ago

I confirm I have version 0.1.4 of the driver installed. I'll repeat the whole process and I'll send again a crash report.

wandering-tales commented 1 year ago

I reproduced the crash and sent a report. I wonder whether these reports are sent to Google at first and then forwarded to developers. I am not an Android developer myself.

wandering-tales commented 1 year ago

I wonder whether the Yubico Authenticator to conflicts somehow with the Key Driver, as maybe it requires exclusive access to the YubiKey.

macearl commented 1 year ago

I wonder whether the Yubico Authenticator to conflicts somehow with the Key Driver, as maybe it requires exclusive access to the YubiKey.

Haven't had a chance to test the new version yet, but the yubico authenticator works fine in combination with another app, e.g. ykdroid. So it shouldn't be an exclusive access problem.

The only hassle is that the authenticator auto starts and you have to manually go back to the previous app and allow the access to the yubikey

intrnl commented 1 year ago

Would it be possible for the biometric unlock function to not require having the YubiKey inserted? I kinda wanted it so that my YubiKey is only required when trying to open my password database for the first time.

Michal78900 commented 1 year ago

Key Driver crashes or throws error when trying to use a Yubikey via NFC. However, I was able to open my database when connected via USB using an adapter. Not sure if NFC not working is a bug or is it just me who doesn't know how to hold the key (I'm fairly new YubiKey user).

I also would appreciate an option for biometric unlock function to not require Yubikey challenge-response, unless the user wants to write changes into the database.

J-Jamet commented 1 year ago

Would it be possible for the biometric unlock function to not require having the YubiKey inserted?

In this case, there is no point in using a Yubikey : https://github.com/Kunzisoft/KeePassDX/issues/8#issuecomment-1212875135

Key Driver crashes or throws error when trying to use a Yubikey via NFC.

https://gitlab.com/kunzisoft/android-hardware-key-driver/-/issues Download the YkDroid mode while waiting for the update. https://github.com/Kunzisoft/KeePassDX/issues/8#issuecomment-1249168078

Michal78900 commented 1 year ago

Download the YkDroid mode while waiting for the update. https://github.com/Kunzisoft/KeePassDX/issues/8#issuecomment-1249168078

Thank you very much! Now it works without any issues via both USB and NFC.

ZenMasta commented 1 year ago

Key Driver is working great for me. KPDX build 3.5.0Beta02. It's as fast as on desktop.

Normally using these keys on phone is super tedious and not nearly as fast as totp because it's a 3-step process.

1) Use your key on www.website "Get Started" 2) choose how to use (BT, NFC, USB) 3) Google Play Services prompt, allow GPS to access my key

With the driver, the's only 1 prompt. I love it!

j6b72 commented 1 year ago

Google Pixel 6P: The provided YkDroid-Mod works flawlessly via NFC, while the Key Driver just vibrates as soon as I swipe my key. No interesting stuff from logcat, but I can provide the logs if required.

Either way, thank you so much for your efforts!

pmorange commented 1 year ago

Hi, currently not working on a Galaxy S22 Ultra. I have the latest beta of KeepassDX and the latest version of the Key Driver. What happens is ... nothing : the screen changes for me to pass my Yubikey. I get it close to my phone, it vibrates, but then nothing happens. The screen of the key driver keeps on waiting. I'm not sure how I can get logs to you. Also, when I go back the password field gets resetted.

macearl commented 1 year ago

I'm also still having problems with the new 0.1.5

I've disabled my yubico authenticator before testing to exclude the automatic app switching as a possible cause.

If I have my yubikey already attached the key driver asks me it touch the button and then tells me there was a problem and I should reconnect my yubikey.

If I reconnect it or if it was not already connected I get the prompt to allow access to the yubikey and as soon as I confirm this the app crashes with the following error:

FATAL EXCEPTION: main
Process: com.kunzisoft.hardware.key, PID: 15598
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.yubikey.intent.action.USB_PERMISSION_REQUEST flg=0x10 } in com.kunzisoft.hardware.key.ConnectionManager@dbb852e
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1689)
    at android.app.LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0.run(Unknown Source:2)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7870)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.hardware.usb.UsbDevice.getVendorId()' on a null object reference
    at com.kunzisoft.hardware.yubikey.challenge.UsbYubiKey$Type.lookupDeviceType(UsbYubiKey.java:121)
    at com.kunzisoft.hardware.yubikey.challenge.UsbYubiKey$Type.isDeviceKnown(UsbYubiKey.java:131)
    at com.kunzisoft.hardware.key.ConnectionManager.requestPermission(ConnectionManager.kt:224)
    at com.kunzisoft.hardware.key.ConnectionManager.onReceive(ConnectionManager.kt:164)
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1679)
    ... 9 more
J-Jamet commented 1 year ago

Can you test the latest release 0.1.7, it should solve the crash problems and allow better error handling. It is now possible to manually restart an NFC scan.