B4J Library SSHJ - ssh, scp, sftp for Java

This is a wrapper for: https://github.com/hierynomus/sshj

Dependencies:
#AdditionalJar: slf4j-api-1.7.25
#AdditionalJar: sshj-0.23.0
#AdditionalJar: eddsa-0.2.0
#AdditionalJar: bcprov-jdk15on-159



You can download this libraries from:
slf4j-api-1.7.25: https://mvnrepository.com/artifact/org.slf4j/slf4j-api
sshj-0.23.0: https://mvnrepository.com/artifact/com.hierynomus/sshj
eddsa-0.2.0: https://mvnrepository.com/artifact/net.i2p.crypto/eddsa
(B4J) bcprov-jdk15on-159: https://www.bouncycastle.org/latest_releases.html
(B4A) prov-1.58.0.0.jar: https://mvnrepository.com/artifact/com.madgag.spongycastle/prov

*NOTE1* I tested this only with B4J, it should work for Android too!
*NOTE2* Also when running in Release you should set #MergeLibraries: False because of the bouncy castle dependency (bcprov-jdk15on-159) which is a signed jar, and when running with #MergeLibraries: True that jar is decompiled and compiled in your jar and therefore losses its signing.
*NOTE3* For Android you need to download spongy castle instead of bouncy castle. You can download it from https://mvnrepository.com/artifact/com.madgag.spongycastle/prov. I don't know if NOTE2 applies in this case.

First steps:
B4X:
    Dim ssh As SSHJ
    ssh.Initialize("ssh")
    '...... or ......
    ssh.Initialize2("ssh", 15) ' where 15 is the KeepAliveInterval - usefull for portforward and future sftp.
As connecting through ssh to a server wants to mean that is secure you have to add the server hostkey:
B4X:
ssh.LoadKnownHosts 'loads the known_hosts file from some default locations.
'or
ssh.LoadKnownHosts2("/tmp/known_hosts")
'or
ssh.AddHostKeyVerifier("SHA1:2Fo8c/96zv32xc8GZWbOGYOlRak=")
'or finnaly if you really trust the server and do not want to verify it's key
ssh.AddHostKeyPromiscuousVerifier
Next step is the authentication. You can supply multiple authentication methods:
B4X:
ssh.AddAuthPassword("youruserpass")
'or/and
ssh.AddAuthPublicKey("/location/to/my/key", "null if not encrypted")
'or/and
ssh.AddAuthPublicKey2("key-key-key-key...", "empty string if public key is in private key string", "null if not encrypted")
Finnaly now we connect:
B4X:
ssh.Connect("hostname/ip", 22, "yourusername")

All the execution methods (read details in ide) - Exec, Shell, SCPUpload, SCPDownload, LocalPortforwarder, RemotePortForwarder and all methods of SFTPClient - are async and work with Wait For feature of B4X.

Like always if you encounter problems i will do my best to help, but I'm no expert!

Edit by Erel: You need to add this line for it to work with the built-in packager:
B4X:
#PackagerProperty: VMArgs = --add-opens b4j/org.bouncycastle.jcajce.provider.asymmetric.ec=java.base
 

Attachments

  • SSHJ-v1.40.zip
    46.8 KB · Views: 625
Last edited by a moderator:

mindful

Active Member
Licensed User
I do not use Java 9.

When I do MergeLibraries: True in release mode and using the sshj library the following errors are shown:
B4X:
10:45:07.244 INFO Registration of Security Provider 'org.bouncycastle.jce.provider.BouncyCastleProvider' unexpectedly failed - net.schmizz.sshj.common.SecurityUtils [main]
java.lang.SecurityException: JCE cannot authenticate the provider BC
........ (more lines - stacktrace)
Caused by: java.util.jar.JarException: file:/C:/WORK/DEV/B4J/TestProject/Objects/TestProject.jar has unsigned entries - anywheresoftware/b4a/AbsObjectWrapper.class
    at javax.crypto.JarVerifier.verifySingleJar(JarVerifier.java:502)
    at javax.crypto.JarVerifier.verifyJars(JarVerifier.java:363)
    at javax.crypto.JarVerifier.verify(JarVerifier.java:289)
    at javax.crypto.JceSecurity.verifyProviderJar(JceSecurity.java:164)
    at javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:190)
    at javax.crypto.JceSecurity.getInstance(JceSecurity.java:114)
    ... 16 common frames omitted
10:45:07.244 INFO BouncyCastle not registered, using the default JCE provider - net.schmizz.sshj.common.SecurityUtils [main]
10:45:07.247 INFO Creating new SecureRandom. - net.schmizz.sshj.transport.random.JCERandom [main]
10:45:07.378 WARN Cannot find any provider supporting CAST5/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.378 WARN Cannot find any provider supporting CAST5/CTR/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.378 WARN Cannot find any provider supporting IDEA/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.378 WARN Cannot find any provider supporting IDEA/CTR/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.379 WARN Cannot find any provider supporting Serpent/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.379 WARN Cannot find any provider supporting Serpent/CTR/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.379 WARN Cannot find any provider supporting Serpent/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.379 WARN Cannot find any provider supporting Serpent/CTR/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.379 WARN Cannot find any provider supporting Serpent/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.379 WARN Cannot find any provider supporting Serpent/CTR/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.381 WARN Cannot find any provider supporting Twofish/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.381 WARN Cannot find any provider supporting Twofish/CTR/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.381 WARN Cannot find any provider supporting Twofish/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.381 WARN Cannot find any provider supporting Twofish/CTR/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.382 WARN Cannot find any provider supporting Twofish/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.382 WARN Cannot find any provider supporting Twofish/CTR/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.382 WARN Cannot find any provider supporting Twofish/CBC/NoPadding - net.schmizz.sshj.DefaultConfig [main]
10:45:07.383 WARN Disabling high-strength ciphers: cipher strengths apparently limited by JCE policy - net.schmizz.sshj.DefaultConfig [main]
10:45:07.408 INFO Client identity string: SSH-2.0-SSHJ_0.24.0 - net.schmizz.sshj.transport.TransportImpl [main]
10:45:07.419 INFO Server identity string: SSH-2.0-OpenSSH_7.4 - net.schmizz.sshj.transport.TransportImpl [main]
10:45:07.579 ERROR Dying because - BouncyCastle is required to read a key of type ecdsa-sha2-nistp256 - net.schmizz.sshj.transport.TransportImpl [reader]
net.schmizz.sshj.common.SSHRuntimeException: BouncyCastle is required to read a key of type ecdsa-sha2-nistp256
........ (more lines - stacktrace)
10:45:07.579 INFO Disconnected - UNKNOWN - net.schmizz.sshj.transport.TransportImpl [reader]
10:45:07.580 ERROR <<kex done>> woke to: net.schmizz.sshj.transport.TransportException: BouncyCastle is required to read a key of type ecdsa-sha2-nistp256 - net.schmizz.concurrent.Promise [main]
10:45:07.581 ERROR net.schmizz.sshj.transport.TransportException: BouncyCastle is required to read a key of type ecdsa-sha2-nistp256 [main]
net.schmizz.sshj.transport.TransportException: BouncyCastle is required to read a key of type ecdsa-sha2-nistp256
........ (more lines - stacktrace)

As you can see the server which I am connecting to requires BouncyCastle to read my ssh key (BouncyCastle is required to read a key of type ecdsa-sha2-nistp256) and BouncyCastle can't be registered because it isn't singed (JCE cannot authenticate the provider BC) because it has been modified.

When you set MergeLibraries: True the IDE "extracts" all data from the libraries and additional jars you have in your project and places then in one jar file. To do this it needs to extract the contents of bcprov-jdk15on-159.jar (which is signed and can be verified) and place then in project one jar file, therefore it loses it signing.

Maybe it works for you because of Java 9 or maybe the device you are connecting to doesn't have any strong chipers.
 

JackKirk

Well-Known Member
Licensed User
maybe the device you are connecting to doesn't have any strong ciphers.
This is entirely conceivable:):):)

If nothing else I've learnt a bit.

Thanks for all your efforts and patience...
 

CaptKronos

Active Member
Licensed User
Resurrecting an earlier question, has anyone managed to get this library to work with Android?

Using:
B4X:
#AdditionalJar: slf4j-api-1.7.25
#AdditionalJar: sshj-0.23.0
#AdditionalJar: eddsa-0.2.0
#AdditionalJar: prov-1.58.0.0.jar
and
B4X:
dim ssh As SSHJ
ssh.Initialize("ssh")
I get the following error on ssh.initalize:
B4X:
java.lang.NoClassDefFoundError: Failed resolution of: Lorg/spongycastle/util/Strings;
    at org.spongycastle.jcajce.provider.config.ProviderConfigurationPermission.calculateMask(ProviderConfigurationPermission.java:69)
    at org.spongycastle.jcajce.provider.config.ProviderConfigurationPermission.<init>(ProviderConfigurationPermission.java:63)
    .
    .
    .
Checking the file prov-1.58.0.0.jar I note that the folder org/spongycastle/util does not exist so the 'failed resolution' error is not surprising.

Thanks.
 

mindful

Active Member
Licensed User
@CaptKronos After you use it can you please confirm or infirm that it works with android ? And also if this works please post what Additional Jars are you using so that everyone can use it. Thanks
 

CaptKronos

Active Member
Licensed User
Yes, it works. Or I believe it is working. Using:
B4X:
#AdditionalJar: slf4j-api-1.7.25
#AdditionalJar: sshj-0.23.0
#AdditionalJar: eddsa-0.2.0
#AdditionalJar: prov-1.58.0.0.jar 
#AdditionalJar: core-1.58.0.0.jar
I now get as far as the Connect statement:
B4X:
    ssh.Initialize("ssh")
    ssh.AddHostKeyPromiscuousVerifier
    ssh.AddAuthPassword("xxxx")
    ssh.Connect("192.168.1.11", 22, "yyy")
at which point I get the error:
B4X:
net.schmizz.sshj.transport.TransportException: Unable to reach a settlement: [diffie-hellman-group1-sha1, diffie-hellman-group-exchange-sha1] and [curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group16-sha512, diffie-hellman-group18-sha512, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1]
so I now better try and find an acceptable crypto protocol for both client and server.
 

CaptKronos

Active Member
Licensed User
Using 0.26.0 I now get the following error on ssh.Connect
B4X:
java.lang.NoClassDefFoundError: Failed resolution of: Lorg/bouncycastle/crypto/ec/CustomNamedCurves;
    at net.schmizz.sshj.transport.kex.Curve25519DH.getCurve25519Params(Curve25519DH.java:60)
    at net.schmizz.sshj.transport.kex.Curve25519SHA256.initDH(Curve25519SHA256.java:44)
    at net.schmizz.sshj.transport.kex.AbstractDHG.init(AbstractDHG.java:46)
    at net.schmizz.sshj.transport.KeyExchanger.gotKexInit(KeyExchanger.java:236)
    at net.schmizz.sshj.transport.KeyExchanger.handle(KeyExchanger.java:356)
    at net.schmizz.sshj.transport.TransportImpl.handle(TransportImpl.java:503)
    at net.schmizz.sshj.transport.Decoder.decode(Decoder.java:102)
    at net.schmizz.sshj.transport.Decoder.received(Decoder.java:170)
    at net.schmizz.sshj.transport.Reader.run(Reader.java:59)
Caused by: java.lang.ClassNotFoundException: Didn't find class "org.bouncycastle.crypto.ec.CustomNamedCurves" on path: DexPathList[[zip file "/data/app/b4a.example-HlIGvsG5aKzjntCHS_52og==/base.apk"],nativeLibraryDirectories=[/data/app/b4a.example-HlIGvsG5aKzjntCHS_52og==/lib/arm64, /system/lib64, /system/vendor/lib64]]
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    ... 9 more
It seems to be calling bouncycastle rather than spongycastle.
 

CaptKronos

Active Member
Licensed User
Going back to sshj-0.23.0 and enabling the less than secure protocols (e.g. diffie-hellman-group1-sha1) at the server end, and all works. Obviously it would be nice not to have to enable those protocols!
 

mindful

Active Member
Licensed User
I will have to dig into this as this is not a wrapper error, but a sshj library error. I can't express any timeline because I am working on other stuff.
 

CaptKronos

Active Member
Licensed User
Just for completeness I have also tried sshj-0.24.0 and receive the same error message as with 0.26.0. So something must have changed between 23 and 24.
 

Dadaista

Active Member
Licensed User
Hi

I get this error in log
B4X:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

I saw this but, no idea :(

This is in the aplication
B4X:
#AdditionalJar: slf4j-api-1.7.25
#AdditionalJar: sshj-0.26.0
#AdditionalJar: eddsa-0.3.0
#AdditionalJar: bcprov-jdk15on-160
#MergeLibraries: true



What can I do to solved?
 

hears

Active Member
Licensed User
Can you move this project to B4A ?
 

DonManfred

Expert
Licensed User

NagyLajos

Member
Licensed User
Plase help me!
My project run in debug mode good, but release mode run with error:

net.schmizz.sshj.transport.TransportException: Unable to reach a settlement: [diffie-hellman-group1-sha1, diffie-hellman-group-exchange-sha1] and [curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group14-sha1]
at net.schmizz.sshj.transport.Proposal.firstMatch(Proposal.java:145)
at net.schmizz.sshj.transport.Proposal.negotiate(Proposal.java:128)
at net.schmizz.sshj.transport.KeyExchanger.gotKexInit(KeyExchanger.java:224)
at net.schmizz.sshj.transport.KeyExchanger.handle(KeyExchanger.java:356)
at net.schmizz.sshj.transport.TransportImpl.handle(TransportImpl.java:503)
at net.schmizz.sshj.transport.Decoder.decode(Decoder.java:102)
at net.schmizz.sshj.transport.Decoder.received(Decoder.java:170)
at net.schmizz.sshj.transport.Reader.run(Reader.java:59)

Libs:
#AdditionalJar: sshj-0.24.0.jar
#AdditionalJar: slf4j-api-1.7.26.jar
#AdditionalJar: slf4j-nop-1.7.26.jar
#AdditionalJar: eddsa-0.3.0.jar
#AdditionalJar: bcprov-jdk15on-161.jar

Thanks.....
 
Top