Closed gujjwal00 closed 9 months ago
Fixed in https://github.com/gujjwal00/avnc/commit/9a66581c92f6f87d9353596328e2047bf2820caf v2.3.1 is now available.
Unfortunately SSH-tunneling is still broken for me on v2.3.1 (F-Droid Build).
I've tried with a fresh reinstall. Direct connections via :5900 are working, ssh-tunneled ones worked flawlessly up to (incl.) v2.2.3.
On v2.3.1 (as on v2.3.0) they reproducably produce the following error message:
( There was a problem while connecting to 192.168.XXX.XX:22 )
On the target system sshd
(OpenSSH_8.9p1
) logs the following at connection attempt:
sshd[2006904]: Connection closed by 192.168.XXX.XX port 49168 [preauth]
avnc logs at connection attempt:
--------- beginning of main
25632 25667 E ReceiverCoroutine: Connection failed
25632 25667 E ReceiverCoroutine: java.io.IOException: There was a problem while connecting to 192.168.XXX.XX:22
25632 25667 E ReceiverCoroutine: at com.trilead.ssh2.Connection.connect(Connection.java:154)
25632 25667 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel.access$connect(VncViewModel.kt:56)
25632 25667 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel$launchConnection$1.invokeSuspend(VncViewModel.kt:41)
25632 25667 E ReceiverCoroutine: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:9)
25632 25667 E ReceiverCoroutine: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:111)
25632 25667 E ReceiverCoroutine: at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:4)
25632 25667 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:3)
25632 25667 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:94)
25632 25667 E ReceiverCoroutine: Caused by: java.io.IOException: Key exchange was not finished, connection is closed.
25632 25667 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager.getConnectionInfo(TransportManager.java:39)
25632 25667 E ReceiverCoroutine: at com.trilead.ssh2.Connection.connect(Connection.java:79)
25632 25667 E ReceiverCoroutine: ... 7 more
25632 25667 E ReceiverCoroutine: Caused by: java.io.IOException: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
25632 25667 E ReceiverCoroutine: at com.trilead.ssh2.crypto.dh.Curve25519Exchange.init(Curve25519Exchange.java:85)
25632 25667 E ReceiverCoroutine: at com.trilead.ssh2.transport.KexManager.handleMessage(KexManager.java:381)
25632 25667 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager.receiveLoop(TransportManager.java:638)
25632 25667 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager$1.run(TransportManager.java:4)
25632 25667 E ReceiverCoroutine: at java.lang.Thread.run(Thread.java:923)
25632 25667 E ReceiverCoroutine: Caused by: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
25632 25667 E ReceiverCoroutine: at com.google.crypto.tink.subtle.X25519.computeSharedSecret(X25519.java:94)
25632 25667 E ReceiverCoroutine: at com.trilead.ssh2.crypto.dh.Curve25519Exchange.init(Curve25519Exchange.java:75)
25632 25667 E ReceiverCoroutine: ... 4 more
I tried v2.3.1 from F-Droid, but I can't reproduce this. I am able to connect with RSA & Ed25519 keys of different sizes. Can you please try this unoptimized APK: app-debug.zip
About that stacktrace: It looks impossible to me, unless R8 literally removed functioning code. Can you upload the APK you are testing with?
Thank you for your fast reaction.
I forgot to mention that I'm not using key-based but password-based ssh auth on the target system in question - just in case that matters. Edit: It doesn't seem to matter as a connection attempt with an ssh key (generated in termux) fails, too.
I tried with the debug-apk (once using password- and once using key-based auth) and it works perfectly fine. At connection attempt I'm getting the following prompt (not sure if thats new, since I didn't reinstall / re-add my servers for some time now): After accepting the connection works as it used to in previous versions.
The APK I'm using is the one from F-Droid. Since AVNCs APK is multi-arch you must have used the same one for testing as I did. I can still reupload it here nonetheless: com.gaurav.avnc_28.zip Edit: Just to rule out any possible incompatibillities introduced by F-Droids compiling process I tested with your APK from github releases and got the exact same result.
Yet another edit: I tried the F-Droid Build with another client device, running LineageOS 20 (Android 13). There it (ssh-tunnel with password-based auth) does work. The original client device in question is still running Android 11, so it seems to depend upon the android version. If you need any additional logs / information, please let me know. I'm happy to help debugging this issue.
I tried with the debug-apk (once using password- and once using key-based auth) and it works perfectly fine.
So maybe the optimizations done by R8 are causing trouble.
At connection attempt I'm getting the following prompt (not sure if thats new, since I didn't reinstall / re-add my servers for some time now):
Yeah, that's normal for first connection. It is similar to ~/.ssh/known_hosts
file used by ssh
client.
The APK I'm using is the one from F-Droid. Since AVNCs APK is multi-arch you must have used the same one for testing as I did. I can still reupload it here nonetheless: com.gaurav.avnc_28.zip Edit: Just to rule out any possible incompatibillities introduced by F-Droids compiling process I tested with your APK from github releases and got the exact same result.
Yeah, that rules out any APK related issue.
I tried the F-Droid Build with another client device, running LineageOS 20 (Android 13). There it (ssh-tunnel with password-based auth) does work. The original client device in question is still running Android 11, so it seems to depend upon the android version.
I have tested v2.3.1 to work correctly on following platforms:
If you need any additional logs / information, please let me know. I'm happy to help debugging this issue.
Different Android Gradle Plugin versions uses different versions of R8. Current v2.3.1 is built with AGP 8.2.0. So its possible that this particular version is the culprit.
I am attaching two optimized APKs here:
Please test with both of these. For the version you fail to connect successfully, please post the full logs (if you can use adb logcat
that would be great, otherwise just use Logs dialog in AVNC settings).
Please test with both of these. For the version you fail to connect successfully, please post the full logs (if you can use adb logcat that would be great, otherwise just use Logs dialog in AVNC settings).
I tested both versions. Both fail to connect. (SSH-tunnel with password-auth) I tried to capture the related logcat events but as a grep for com.gaurav.avnc
or its UID doesn't contain the actual java exception and the full, unfiltered logcat contains several tens of pages of unrelated info during the few seconds the test takes I can only provide the logs from the AVNC log dialog.
If you can give me a hint how to filter (e.g. what to grep for) the logcat output for only the relevant information I would repeat the test to provide logcat output.
AVNC-Log of a connection attempt using app-ci-8.1.4.apk
:
--------- beginning of main
23432 23467 E ReceiverCoroutine: Connection failed
23432 23467 E ReceiverCoroutine: java.io.IOException: There was a problem while connecting to 192.168.XXX.XX:22
23432 23467 E ReceiverCoroutine: at com.trilead.ssh2.Connection.connect(Connection.java:149)
23432 23467 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel.access$connect(VncViewModel.kt:56)
23432 23467 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel$launchConnection$1.invokeSuspend(VncViewModel.kt:41)
23432 23467 E ReceiverCoroutine: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:9)
23432 23467 E ReceiverCoroutine: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:112)
23432 23467 E ReceiverCoroutine: at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:4)
23432 23467 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:3)
23432 23467 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:96)
23432 23467 E ReceiverCoroutine: Caused by: java.io.IOException: Key exchange was not finished, connection is closed.
23432 23467 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager.getConnectionInfo(TransportManager.java:37)
23432 23467 E ReceiverCoroutine: at com.trilead.ssh2.Connection.connect(Connection.java:82)
23432 23467 E ReceiverCoroutine: ... 7 more
23432 23467 E ReceiverCoroutine: Caused by: java.io.IOException: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
23432 23467 E ReceiverCoroutine: at com.trilead.ssh2.crypto.dh.Curve25519Exchange.init(Curve25519Exchange.java:85)
23432 23467 E ReceiverCoroutine: at com.trilead.ssh2.transport.KexManager.handleMessage(KexManager.java:380)
23432 23467 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager.receiveLoop(TransportManager.java:689)
23432 23467 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager$1.run(TransportManager.java:4)
23432 23467 E ReceiverCoroutine: at java.lang.Thread.run(Thread.java:923)
23432 23467 E ReceiverCoroutine: Caused by: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
23432 23467 E ReceiverCoroutine: at com.google.crypto.tink.subtle.X25519.computeSharedSecret(X25519.java:94)
23432 23467 E ReceiverCoroutine: at com.trilead.ssh2.crypto.dh.Curve25519Exchange.init(Curve25519Exchange.java:75)
23432 23467 E ReceiverCoroutine: ... 4 more
AVNC-Log of a connection attempt using app-ci-8.2.2.apk
:
--------- beginning of main
25629 25664 E ReceiverCoroutine: Connection failed
25629 25664 E ReceiverCoroutine: java.io.IOException: There was a problem while connecting to 192.168.XXX.XX:22
25629 25664 E ReceiverCoroutine: at com.trilead.ssh2.Connection.connect(Connection.java:154)
25629 25664 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel.access$connect(VncViewModel.kt:56)
25629 25664 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel$launchConnection$1.invokeSuspend(VncViewModel.kt:41)
25629 25664 E ReceiverCoroutine: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:9)
25629 25664 E ReceiverCoroutine: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:111)
25629 25664 E ReceiverCoroutine: at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:4)
25629 25664 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:3)
25629 25664 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:94)
25629 25664 E ReceiverCoroutine: Caused by: java.io.IOException: Key exchange was not finished, connection is closed.
25629 25664 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager.getConnectionInfo(TransportManager.java:39)
25629 25664 E ReceiverCoroutine: at com.trilead.ssh2.Connection.connect(Connection.java:79)
25629 25664 E ReceiverCoroutine: ... 7 more
25629 25664 E ReceiverCoroutine: Caused by: java.io.IOException: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
25629 25664 E ReceiverCoroutine: at com.trilead.ssh2.crypto.dh.Curve25519Exchange.init(Curve25519Exchange.java:85)
25629 25664 E ReceiverCoroutine: at com.trilead.ssh2.transport.KexManager.handleMessage(KexManager.java:381)
25629 25664 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager.receiveLoop(TransportManager.java:638)
25629 25664 E ReceiverCoroutine: at com.trilead.ssh2.transport.TransportManager$1.run(TransportManager.java:4)
25629 25664 E ReceiverCoroutine: at java.lang.Thread.run(Thread.java:923)
25629 25664 E ReceiverCoroutine: Caused by: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
25629 25664 E ReceiverCoroutine: at com.google.crypto.tink.subtle.X25519.computeSharedSecret(X25519.java:94)
25629 25664 E ReceiverCoroutine: at com.trilead.ssh2.crypto.dh.Curve25519Exchange.init(Curve25519Exchange.java:75)
25629 25664 E ReceiverCoroutine: ... 4 more
25629 25651 W System : A resource failed to call release.
If you can give me a hint how to filter (e.g. what to grep for) the logcat output for only the relevant information I would repeat the test to provide logcat output.
Well, the test didn't work so just AVNC log is fine for now.
Please test these: app-ci-ssh21.zip app-ci-ssh23.zip
These have different SSH library versions. I think atleast the first one will work correctly.
With app-ci-ssh21
the connection works, The attempt with app-ci-ssh23
results in the error Disconnected
.
app-ci-ssh21
--------- beginning of main
26292 26330 E SSHTest : false
26292 26330 E SSHTest : redacted
26292 26330 E SSHTest : redacted
26292 26903 I EngineFactory: Provider GmsCore_OpenSSL not available
26292 26326 D OpenGLRenderer: endAllActiveAnimators on 0xb400007543f12410 (RippleDrawable) with handle 0xb400007463e18b60
26292 26330 I NativeVnc: Received protocol version 3.8
26292 26330 I NativeVnc: VNC server supports protocol version 3.8 (viewer 3.8)
26292 26330 I NativeVnc: We have 1 security types to read
26292 26330 I NativeVnc: 0) Received security type 2
26292 26330 I NativeVnc: Selecting security type 2 (0/1 in the list)
26292 26330 I NativeVnc: Selected Security Scheme 2
26292 26330 I NativeVnc: VNC authentication succeeded
26292 26330 I NativeVnc: Desktop name "redacted:0"
26292 26330 I NativeVnc: Connected to VNC server, using protocol version 3.8
26292 26330 I NativeVnc: VNC server default format:
26292 26330 I NativeVnc: 32 bits per pixel.
26292 26330 I NativeVnc: Least significant byte first in each pixel.
26292 26330 I NativeVnc: TRUE colour: max red 255 green 255 blue 255, shift red 16 green 8 blue 0
26292 26901 D ShaderCompiler:
26292 26901 I chatty : uid=10582(com.gaurav.avnc.ci) identical 1 line
26292 26901 D ShaderCompiler:
26292 26330 I NativeVnc: client2server supported messages (bit flags)
26292 26330 I NativeVnc: 00: 00ff 0081 0000 0000 - 0000 0000 0000 0000
26292 26330 I NativeVnc: 08: 0000 0000 0000 0000 - 0000 0000 0000 0000
26292 26330 I NativeVnc: 10: 0000 0000 0000 0000 - 0000 0000 0000 0000
26292 26330 I NativeVnc: 18: 0000 0000 0000 0000 - 0000 0000 0000 0008
26292 26330 I NativeVnc: server2client supported messages (bit flags)
26292 26330 I NativeVnc: 00: 001f 0080 0000 0000 - 0000 0000 0000 0000
26292 26330 I NativeVnc: 08: 0000 0000 0000 0000 - 0000 0000 0000 0000
26292 26330 I NativeVnc: 10: 0000 0000 0000 0000 - 0000 0000 0000 0000
26292 26330 I NativeVnc: 18: 0000 0000 0000 0000 - 0000 0000 0000 0000
26292 26330 I NativeVnc: Connected to Server "unknown (LibVNCServer 0.9.13)"
app-ci-ssh23
--------- beginning of main
30257 30301 E SSHTest : true
30257 30301 E ReceiverCoroutine: Connection failed
30257 30301 E ReceiverCoroutine: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
30257 30301 E ReceiverCoroutine: at com.google.crypto.tink.subtle.X25519.computeSharedSecret(X25519.java:94)
30257 30301 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel.access$connect(VncViewModel.kt:53)
30257 30301 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel$launchConnection$1.invokeSuspend(VncViewModel.kt:41)
30257 30301 E ReceiverCoroutine: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:9)
30257 30301 E ReceiverCoroutine: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:111)
30257 30301 E ReceiverCoroutine: at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:4)
30257 30301 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:3)
30257 30301 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:94)
Ok, now we know the problematic combination: The issue happens with sshlib 2.2.23, when compiled with AGP 8.1+, with optimizations ON, on some specific devices.
About the issue: sshlib uses tink crypto library. It was updated in v2.2.23. One of the things that changed is how two byte arrays are compared. Newer version uses Java's MessageDigest.isEqual()
method, instead of custom check. For some inexplicable reason, this method is returning true
when comparing two different arrays. To test this I added a test in previous APKs. Look at the first line of logs for app-ci-ssh23
:
30257 30301 E SSHTest : true
This should have been false
like in case of app-ci-ssh21
. This incorrect behavior trips up the tink library during key exchange, and a value which should not have been equal to, ends up being equal to 0000000000000000000000000000000000000000000000000000000000000000
, resulting in that exception.
I am adding couple more APKs, with a bit more testing. Please post the logs for these: app-ci-test.zip app-debug-test.zip
Also, please tell me your device model and more about Android version (is it a custom ROM like MIUI or OneUI?)
app-ci.apk
(failed with Disconnected
):
--------- beginning of main
32332 32378 D SSHTest : b1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
32332 32378 D SSHTest : b2 = [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
32332 32378 D SSHTest : MessageDigest.isEqual(b1, b2) = true
32332 32378 D SSHTest : Bytes.equal(b1, b2) = true
32332 32378 D SSHTest : d = [20 numbers between -119 and 118, redacted]
32332 32378 D SSHTest : 2nd MessageDigest.isEqual(b1, b2) = true
32332 32378 D SSHTest : 2nd Bytes.equal(b1, b2) = true
32332 32378 E ReceiverCoroutine: Connection failed
32332 32378 E ReceiverCoroutine: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
32332 32378 E ReceiverCoroutine: at com.google.crypto.tink.subtle.X25519.computeSharedSecret(X25519.java:94)
32332 32378 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel.access$connect(VncViewModel.kt:193)
32332 32378 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel$launchConnection$1.invokeSuspend(VncViewModel.kt:41)
32332 32378 E ReceiverCoroutine: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:9)
32332 32378 E ReceiverCoroutine: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:111)
32332 32378 E ReceiverCoroutine: at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:4)
32332 32378 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:3)
32332 32378 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:94)
app-debug-test
(connection works):
--------- beginning of main
4813 4860 D SSHTest : b1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4813 4860 D SSHTest : b2 = [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4813 4860 D SSHTest : MessageDigest.isEqual(b1, b2) = false
4813 4860 D SSHTest : Bytes.equal(b1, b2) = false
4813 4860 D SSHTest : d = [20 numbers between -119 and 118, redacted]
4813 4860 D SSHTest : 2nd MessageDigest.isEqual(b1, b2) = false
4813 4860 D SSHTest : 2nd Bytes.equal(b1, b2) = false
4813 4860 E SSHTest : [redacted
4813 4860 E SSHTest : [redacted
4813 4856 D OpenGLRenderer: endAllActiveAnimators on 0xb400007543ece550 (RippleDrawable) with handle 0xb400007463e16ee0
4813 4860 I NativeVnc: Received protocol version 3.8
4813 4860 I NativeVnc: VNC server supports protocol version 3.8 (viewer 3.8)
4813 4860 I NativeVnc: We have 1 security types to read
4813 4860 I NativeVnc: 0) Received security type 2
4813 4860 I NativeVnc: Selecting security type 2 (0/1 in the list)
4813 4860 I NativeVnc: Selected Security Scheme 2
4813 4860 I NativeVnc: VNC authentication succeeded
4813 4860 I NativeVnc: Desktop name "redacted:0"
4813 4860 I NativeVnc: Connected to VNC server, using protocol version 3.8
4813 4860 I NativeVnc: VNC server default format:
4813 4860 I NativeVnc: 32 bits per pixel.
4813 4860 I NativeVnc: Least significant byte first in each pixel.
4813 4860 I NativeVnc: TRUE colour: max red 255 green 255 blue 255, shift red 16 green 8 blue 0
4813 5157 D ShaderCompiler:
4813 5157 I chatty : uid=10586(com.gaurav.avnc.debug) identical 1 line
4813 5157 D ShaderCompiler:
4813 5157 D ShaderCompiler: Program [3] validation result: 1
4813 5157 D ShaderCompiler: Program [3] validation log:
4813 4860 I NativeVnc: client2server supported messages (bit flags)
4813 4860 I NativeVnc: 00: 00ff 0081 0000 0000 - 0000 0000 0000 0000
4813 4860 I NativeVnc: 08: 0000 0000 0000 0000 - 0000 0000 0000 0000
4813 4860 I NativeVnc: 10: 0000 0000 0000 0000 - 0000 0000 0000 0000
4813 4860 I NativeVnc: 18: 0000 0000 0000 0000 - 0000 0000 0000 0008
4813 4860 I NativeVnc: server2client supported messages (bit flags)
4813 4860 I NativeVnc: 00: 001f 0080 0000 0000 - 0000 0000 0000 0000
4813 4860 I NativeVnc: 08: 0000 0000 0000 0000 - 0000 0000 0000 0000
4813 4860 I NativeVnc: 10: 0000 0000 0000 0000 - 0000 0000 0000 0000
4813 4860 I NativeVnc: 18: 0000 0000 0000 0000 - 0000 0000 0000 0000
4813 4860 I NativeVnc: Connected to Server "unknown (LibVNCServer 0.9.13)"
The device which on which the problems occur, is running an OmniROM-Build from mid 2021, based on Android 11. The device manufacturer / model seems irrelevant to me, as it ain't running the manufacturer-provided stock ROM anymore.
For comparison: The device it works on is running a much more recent LineageOS 20 version from early 2024, based on Android 13.
Edit: I additionally borrowed an android tablet running a LineageOS 18.1 version from august 2021, based on Android 11 and tested your latest app-ci.apk
on it to rule out any OmniROM-specific incompatibillities. It behaves identically. (Disconnected
)
Here are the logs of testing the app-ci.apk
on LineageOS 18.1:
--------- beginning of main
6794 6823 D SSHTest : b1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
6794 6823 D SSHTest : b2 = [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
6794 6823 D SSHTest : MessageDigest.isEqual(b1, b2) = true
6794 6823 D SSHTest : Bytes.equal(b1, b2) = true
6794 6823 D SSHTest : d = [20 numbers between -119 and 118, redacted]
6794 6823 D SSHTest : 2nd MessageDigest.isEqual(b1, b2) = true
6794 6823 D SSHTest : 2nd Bytes.equal(b1, b2) = true
6794 6823 E ReceiverCoroutine: Connection failed
6794 6823 E ReceiverCoroutine: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
6794 6823 E ReceiverCoroutine: at com.google.crypto.tink.subtle.X25519.computeSharedSecret(X25519.java:94)
6794 6823 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel.access$connect(VncViewModel.kt:193)
6794 6823 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel$launchConnection$1.invokeSuspend(VncViewModel.kt:41)
6794 6823 E ReceiverCoroutine: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:9)
6794 6823 E ReceiverCoroutine: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:111)
6794 6823 E ReceiverCoroutine: at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:4)
6794 6823 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:3)
6794 6823 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:94)
6794 6808 I .gaurav.avnc.c: Background concurrent copying GC freed 78363(3802KB) AllocSpace objects, 4(80KB) LOS objects, 51% free, 5868KB/11MB, paused 500us total 103.379ms
6794 6810 W System : A resource failed to call release.
6794 6823 D SSHTest : b1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 6794 6823 D SSHTest : b2 = [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 6794 6823 D SSHTest : MessageDigest.isEqual(b1, b2) = true 6
This is the problematic part. As you can see, b1 & b2 byte arrays are different at first byte, but MessageDigest.isEqual(b1, b2)
is returning true here. And it only seems to happen in optimized builds.
At this point, I need to reproduce this locally to be able to find the root cause. Thanks for testing all the APKs.
I don't want to downgrade sshlib because newer version includes fixes for terrapin attack.
6794 6823 D SSHTest : d = [20 numbers between -119 and 118, redacted]
Just as a note, this is SHA1 digest of byte array b2
.
This is the problematic part. As you can see, b1 & b2 byte arrays are different at first byte, but MessageDigest.isEqual(b1, b2) is returning true here. And it only seems to happen in optimized builds. At this point, I need to reproduce this locally to be able to find the root cause. Thanks for testing all the APKs.
I see, thank you for investigating. I'm glad I could be of service. Afaik waydroid still uses an Android 11 based version of LineageOS. Maybe you could try reproducing it on waydroid, as the error does not occur on your Android 11 emulator? Edit: Nope. No need to go down that route. I tested the F-Droid 2.3.1 build on waydroid / LineageOS 11 and the bug didn't occur.
I don't want to downgrade sshlib because newer version includes fixes for terrapin attack.
Sounds reasonable to me.
Just as a note, this is SHA1 digest of byte array b2.
Yeah, I'm by no means an expert in all of this. I just wasn't sure if it was something along the lines of a password hash, so I just redacted it as a precaution.
After quite a bit of testing, I still can't reproduce it. Only reference I found to this bug is this issue: https://github.com/nightscout/AndroidAPS/issues/3039 . This too happens on Android 11, and on specific devices. If you check the logs linked there in first comment, you will find the same exception being thrown as we see here.
So, I want you to please run a few final tests before I chalk it up to an Android bug:
keep
rules after looking through ConnectBot's sources. simple-debug.apk
Debug version
Success: Arrays.equals works as expected
Success: MessageDigest works as expected
simple-release.apk
Release Version
Success: Arrays.equals works as expected
Error: MessageDigest.isEqual(b1, b2) is true
Even though the output of simple-release.apk
certainly does not look like a success I still tried to connect with ConnectBot and got the exact same exception:
Key exchange was not finished, connection is closed.
java.security.InvalidKeyException: Banned public key: 000000000
00000000000000000000000000000000000000
Banned public key: 00000000000000000000000000000000000000000000
000
avnc-ci-keeprules.apk
--------- beginning of main
02-24 14:58:52.069 4808 4854 D SSHTest : b1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
02-24 14:58:52.069 4808 4854 D SSHTest : b2 = [9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
02-24 14:58:52.069 4808 4854 D SSHTest : b1.contentEquals(b2) = false
02-24 14:58:52.072 4808 4854 D SSHTest : MessageDigest.isEqual(b1, b2) = true
02-24 14:58:52.072 4808 4854 D SSHTest : Bytes.equal(b1, b2) = true
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: Connection failed
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: java.security.InvalidKeyException: Banned public key: 0000000000000000000000000000000000000000000000000000000000000000
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: at com.google.crypto.tink.subtle.X25519.computeSharedSecret(X25519.java:94)
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel.access$connect(VncViewModel.kt:141)
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: at com.gaurav.avnc.viewmodel.VncViewModel$launchConnection$1.invokeSuspend(VncViewModel.kt:41)
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:9)
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:111)
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:4)
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:3)
02-24 14:58:52.077 4808 4854 E ReceiverCoroutine: at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:94)
[…] before I chalk it up to an Android bug
Am I interpreting this statement correctly, that this is a (probably rare) android bug which you can't affect, but which you also can't / won't work around somehow in AVNC's code? Because that would be a bummer for me and probably others who arent willing to replace perfectly working devices just because they were declared EOL by their manufacturers, as we would have to stay on AVNC version 2.2.3. Regardless I want to thank you for investigating this appearently rare bug. (And for developing this awesome piece of software, ofc!)
[…] before I chalk it up to an Android bug
Am I interpreting this statement correctly, that this is a (probably rare) android bug
Yes, that's right. Its an Android bug. For reference, this is the code contained in those simple APK:
private void test() {
byte[] b1 = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte[] b2 = new byte[]{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
String arraysResult = Arrays.equals(b1, b2) ? "Error: Arrays.equals(b1, b2) is true" : "Success: Arrays.equals works as expected";
String messageDigestResult = MessageDigest.isEqual(b1, b2) ? "Error: MessageDigest.isEqual(b1, b2) is true" : "Success: MessageDigest works as expected";
String version = BuildConfig.DEBUG ? "Debug version" : "Release Version";
textView.setText(version + "\n\n" + arraysResult + "\n\n" + messageDigestResult);
}
MessageDigest.isEqual(b1, b2)
& Arrays.equals(b1, b2)
are both Java functions, and they should always return false
for these arrays. There is no difference between two simple APKs, other than that the first APK is debugable. So I would guess that its a bug in JIT/pre-compilation.
which you can't affect, but which you also can't / won't work around somehow in AVNC's code?
Yes, there is no workaround other than downgrading sshlib to older version.
Because that would be a bummer for me and probably others who arent willing to replace perfectly working devices just because they were declared EOL by their manufacturers, as we would have to stay on AVNC version 2.2.3.
When I was looking at #81 , I briefly tried to find alternative ssh libraries, but I could not find anything better than Connectbot's library. Not to say Connectbot's sshlib is perfect. I have do shit like this, just to find a port for tunnel.
But recently, I have been using https://github.com/apache/mina-sshd as a dummy server for writing SSH tunnel tests in AVNC. So one possibility is to migrate to that for client side too. Its not flawless though. mina-sshd doesn't officially support Android, and I haven't looked closely at the client-side feature set (and that it doesn't trigger the same bug 😀).
Thanks for clarification and explaining the background in an understandable way. 👍
I'll probably stay on 2.2.3 on that device until it breaks (or you decide to switch to another ssh library), then. Not exactly great from a security point of view, but in terms of usabillity that is already a pretty good status quo imo.
This is caused by the 'full mode' of R8, which breaks sshlib. This mode was off by default, but AGP 8.2 seems to have tuned it on. The issue is only visible in optimized builds.
Thanks to Hiroshi MATSUOKA for reporting this.