209

I'm trying to use Jsch to establish an SSH connection in Java. My code produces the following exception:

com.jcraft.jsch.JSchException: UnknownHostKey: mywebsite.example.
RSA key fingerprint is 22:fb:ee:fe:18:cd:aa:9a:9c:78:89:9f:b4:78:75:b4

I cannot find how to verify the host key in the Jsch documentation. I have included my code below.

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

public class ssh {
    public static void main(String[] arg) {

        try {
            JSch jsch = new JSch();

            //create SSH connection
            String host = "mywebsite.example";
            String user = "username";
            String password = "123456";

            Session session = jsch.getSession(user, host, 22);
            session.setPassword(password);
            session.connect();

        } catch(Exception e) {
            System.out.println(e);
        }
    }
}
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Alex
  • 16,409
  • 6
  • 40
  • 56

13 Answers13

272

I would either:

  1. Try to ssh from the command line and accept the public key (the host will be added to ~/.ssh/known_hosts and everything should then work fine from Jsch) -OR-
  2. Configure JSch to not use "StrictHostKeyChecking" (this introduces insecurities and should only be used for testing purposes), using the following code:

    java.util.Properties config = new java.util.Properties(); 
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    

Option #1 (adding the host to the ~/.ssh/known_hosts file) has my preference.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • 49
    `JSch#setConfig("StrictHostKeyChecking", "no")` will do the same job, but in just one line – yegor256 Mar 31 '12 at 04:32
  • 2
    Side note: I used this feedback to configure my `~/.ssh/config` file to fix the above error when I didn't have access to modify the source code – Adam Rofer Apr 04 '12 at 21:03
  • What did you do to your .ssh/config? I'm having the same error. – Bernard Igiri Aug 11 '12 at 18:39
  • 25
    This is insecure and really shouldn't have been selected as the right answer on that principle. The setKnownHosts() and setFingerPrint() options are the way to do this without ignoring an important aspect of the ssh process. Edit: in my experience, #1 does not work from within some IDE environments like Eclipse. – Rondo Jul 11 '13 at 01:05
  • 1
    It did the job for me inside of eclipse ... just what I needed in a test environment .... – ProfVersaggi Jan 13 '15 at 21:53
  • Please ensure you are using at least version 0.1.53. Earlier versions have similar issues. – codester Jun 29 '16 at 17:51
  • `import static com.jcraft.jsch.JSch.setConfig;` `JSch.setConfig("StrictHostKeyChecking", "no");` – aswzen Nov 08 '16 at 05:05
  • I tried this but still not work, can help on this?https://stackoverflow.com/questions/46766040/java-lang-runtimeexception-com-jcraft-jsch-jschexception-algorithm-negotiation – Panadol Chong Oct 17 '17 at 09:41
72

While the question has been answered in general, I've found myself that there's a case when even existing known_hosts entry doesn't help. This happens when an SSH server sends ECDSA fingerprint and as a result, you'll have an entry like this:

|1|+HASH=|HASH= ecdsa-sha2-nistp256 FINGERPRINT=

The problem is that JSch prefers SHA_RSA and while connecting it will try to compare SHA-RSA fingerprint, which will result with error about "unknown host".

To fix this simply run:

$ ssh-keyscan -H -t rsa example.org >> known_hosts

or complain to Jcraft about prefering SHA_RSA instead of using the local HostKeyAlgorithms setting, although they don't seem to be too eager to fix their bugs.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
user3601487
  • 1,057
  • 1
  • 11
  • 21
  • 2
    We are in a similar case, with `ecdsa-sha2-nistp384`, and your solution work very well. Accordingly to [openssh-keyscan manual](https://man.openbsd.org/ssh-keyscan), and our need, we run `ssh-keyscan -t rsa,ecdsa example.org >> known_hosts`. – taringamberini Feb 19 '18 at 09:57
  • 2
    I had such a problem, but the exception was *JSchException: reject HostKey:* instead of *JSchException: UnknownHostKey* (this might help some other users) – bdulac Feb 12 '19 at 14:22
  • I had to additionally add the setKnownHosts file as proposed by @krishnakumarp – Wolfgang Fahl May 02 '20 at 07:36
46

It is a security risk to avoid host key checking.

JSch uses HostKeyRepository interface and its default implementation KnownHosts class to manage this. You can provide an alternate implementation that allows specific keys by implementing HostKeyRepository. Or you could keep the keys that you want to allow in a file in the known_hosts format and call

jsch.setKnownHosts(knownHostsFileName);

Or with a public key String as below.

String knownHostPublicKey = "mysite.example ecdsa-sha2-nistp256 AAAAE............/3vplY";
jsch.setKnownHosts(new ByteArrayInputStream(knownHostPublicKey.getBytes()));

see Javadoc for more details.

This would be a more secure solution.

Jsch is open source and you can download the source from here. In the examples folder, look for KnownHosts.java to know more details.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
krishnakumarp
  • 8,967
  • 3
  • 49
  • 55
17

Depending on what program you use for ssh, the way to get the proper key could vary. Putty (popular with Windows) uses their own format for ssh keys. With most variants of Linux and BSD that I've seen, you just have to look in ~/.ssh/known_hosts. I usually ssh from a Linux machine and then copy this file to a Windows machine. Then I use something similar to

jsch.setKnownHosts("C:\\Users\\cabbott\\known_hosts");

Assuming I have placed the file in C:\Users\cabbott on my Windows machine. If you don't have access to a Linux machine, try http://www.cygwin.com/

Maybe someone else can suggest another Windows alternative. I find putty's way of handling SSH keys by storing them in the registry in a non-standard format bothersome to extract.

Charity Leschinski
  • 2,886
  • 2
  • 23
  • 40
  • On windows usingh ssh in `cygwin` (you have to download the `openssl` package and dependencies) I have been able to download `~/.ssh/known_hosts`. Thanks to @CharityAbbott. – taringamberini Mar 31 '15 at 10:32
10

Supply the public rsa key of the host :-

String knownHostPublicKey = "mywebsite.example ssh-rsa AAAAB3NzaC1.....XL4Jpmp/";

session.setKnownHosts(new ByteArrayInputStream(knownHostPublicKey.getBytes()));
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Mark Beer
  • 101
  • 1
  • 3
  • 1
    Didn't work for me with jsch version 0.1.50 (always got a NPE in jsch) but with the newest version 0.1.53 its working. – Udo Sep 10 '15 at 14:23
  • will this (String.getBytes()) provide a byte array of unicode-encoded characters, when the Jsch code (Util.byte2str()) expects UTF-8 encoding? – rich p Sep 15 '16 at 22:39
9

You can also simply do

session.setConfig("StrictHostKeyChecking", "no");

It's not secure and it's a workaround not suitable for live environment as it will disable globally known host keys checking.

Amaury D
  • 475
  • 4
  • 7
  • 2
    While this code may help answer the question, code only answers are not high quality. A better answer would explain what the code does, tell where to insert it, explain why this approach was taken, and link to relevant documentation. – Stephen Ostermiller Jun 20 '14 at 10:02
5

You can also execute the following code. It is tested and working.

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;

public class SFTPTest {

    public static void main(String[] args) {
        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("username", "mywebsite.example", 22); //default port is 22
            UserInfo ui = new MyUserInfo();
            session.setUserInfo(ui);
            session.setPassword("123456".getBytes());
            session.connect();
            Channel channel = session.openChannel("sftp");
            channel.connect();
            System.out.println("Connected");
        } catch (JSchException e) {
            e.printStackTrace(System.out);
        } catch (Exception e){
            e.printStackTrace(System.out);
        } finally{
            session.disconnect();
            System.out.println("Disconnected");
        }
    }

    public static class MyUserInfo implements UserInfo, UIKeyboardInteractive {

        @Override
        public String getPassphrase() {
            return null;
        }
        @Override
        public String getPassword() {
            return null;
        }
        @Override
        public boolean promptPassphrase(String arg0) {
            return false;
        }
        @Override
        public boolean promptPassword(String arg0) {
            return false;
        }
        @Override
        public boolean promptYesNo(String arg0) {
            return false;
        }
        @Override
        public void showMessage(String arg0) {
        }
        @Override
        public String[] promptKeyboardInteractive(String arg0, String arg1,
                String arg2, String[] arg3, boolean[] arg4) {
            return null;
        }
    }
}

Please substitute the appropriate values.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
  • Yes, I had added that for my reference. I will remove that. Thanks. – Vishnu Prasad Kallummel Aug 18 '13 at 04:49
  • 1
    this created some kind of weird auth problems when connecting to certain SSH Servers offering keyboard-interactive authentication method. I used it for years to get rid of the Key thing and then got burned just today with a certain server. Because i didnt supplied the PW via getPassword() but directly to the Session object. Keep that in mind. I wouldnt use it anymore. – Logemann Apr 11 '17 at 16:30
2

I lost a lot of time on this stupid issue, and i think the message is quite right "there is not the host in the file i'm accessing" but you can have more than a know_host file around on your system (as example i'm using mobaXterm and it keep it's own inside the installation directory mounting the home from that root).

If you are experiencing : it's working from command line but not form the application try to access to your remote server with ssh and check with verbose -v option which file is currently used an example following:

 ssh -v git@gitlab.com
 OpenSSH_6.2p2, OpenSSL 1.0.1g 7 Apr 2014
 debug1: Reading configuration data /etc/ssh_config
 debug1: Connecting to gitlab.com [104.210.2.228] port 22.
 debug1: Connection established.
 debug1: identity file /home/mobaxterm/.ssh/id_rsa type 1
 debug1: identity file /home/mobaxterm/.ssh/id_rsa-cert type -1
 debug1: identity file /home/mobaxterm/.ssh/id_dsa type -1
 debug1: identity file /home/mobaxterm/.ssh/id_dsa-cert type -1
 debug1: identity file /home/mobaxterm/.ssh/id_ecdsa type -1
 debug1: identity file /home/mobaxterm/.ssh/id_ecdsa-cert type -1
 debug1: Enabling compatibility mode for protocol 2.0
 debug1: Local version string SSH-2.0-OpenSSH_6.2
 debug1: Remote protocol version 2.0, remote software version OpenSSH_7.2p2      Ubuntu-4ubuntu2.1
 debug1: match: OpenSSH_7.2p2 Ubuntu-4ubuntu2.1 pat OpenSSH*
 debug1: SSH2_MSG_KEXINIT sent
 debug1: SSH2_MSG_KEXINIT received
 debug1: kex: server->client aes128-ctr hmac-sha1-etm@openssh.com zlib@openssh.com
 debug1: kex: client->server aes128-ctr hmac-sha1-etm@openssh.com zlib@openssh.com
 debug1: sending SSH2_MSG_KEX_ECDH_INIT
 debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
 debug1: Server host key: RSA b6:03:0e:39:97:9e:d0:e7:24:ce:a3:77:3e:01:42:09
 debug1: Host 'gitlab.com' is known and matches the RSA host key.
 debug1: Found key in /home/mobaxterm/.ssh/known_hosts:19
 debug1: ssh_rsa_verify: signature correct

as you can see the key was found in :

debug1: Found key in /home/mobaxterm/.ssh/known_hosts:19

and not in my windows home under C:\Users\my_local_user\.ssh , i simply merged them and aligned for solve the issue.

Hope this help someone in future

loreii
  • 380
  • 4
  • 13
1

setting known host is better than setting fingure print value.

When you set known host, try to manually ssh (very first time, before application runs) from the box the application runs.

Mark Hildreth
  • 42,023
  • 11
  • 120
  • 109
sreenath V
  • 121
  • 1
  • 1
1

Just substitute "user", "pass", "SSHD_IP". And create a file called known_hosts.txt with the content of the server's ~/.ssh/known_hosts. You will get a shell.

public class Known_Hosts {
public static void main(String[] arg) {
    try {
        JSch jsch = new JSch();
        jsch.setKnownHosts("known_hosts.txt");
        Session session = jsch.getSession("user", "SSHD_IP", 22);
        session.setPassword("pass");
        session.connect();
        Channel channel = session.openChannel("shell");
        channel.setInputStream(System.in);
        channel.setOutputStream(System.out);
        channel.connect();
    } catch (Exception e) {
        System.out.println(e);
    }
  }
}
dalvarezmartinez1
  • 1,385
  • 1
  • 17
  • 26
  • Nope doesn't work for me. Similarly, Eric Leschinski/Rakesh Acharya's answer fails if I comment out `config.put("StrictHostKeyChecking", "no");` A manual `ssh -v` connection reveals the `.ssh/known_hosts` file does contain the key (`ecdsa-sha2-nistp256`) but the code does this: `com.jcraft.jsch.JSchException: UnknownHostKey: 131.132.x.x. RSA key fingerprint is c2:...` `at com.jcraft.jsch.Session.checkHost(Session.java:805)` `at com.jcraft.jsch.Session.connect(Session.java:345)` – Urhixidur Jun 06 '17 at 18:57
  • It's been some time, what I'd try doing, is use the JSCH library version available on June 13th 2013, cause things probably changed in the library since then – dalvarezmartinez1 Jun 08 '17 at 09:21
0

Has anyone been able to solve this problem? I am using Jscp to scp files using public key authentication (i dont want to use password authentication). Help will be appreciated!!!

This stackoverflow entry is about the host-key checking, and there is no relation to the public key authentication.

As for the public key authentication, try the following sample with your plain(non ciphered) private key,

Zon
  • 18,610
  • 7
  • 91
  • 99
ymnk
  • 1,145
  • 7
  • 7
0

I've found the solution in one of the deleted answers written by @Jairo Martínez

Firstly, the server requires to store the host as hashed rsa

ssh-keyscan -H -t rsa SERVER_IP_ADDRESS >> known_hosts_file

In addition, it was required to tell Jsch that the host key is hashed

session.setConfig("HashKnownHosts", "yes");

Marian Klühspies
  • 15,824
  • 16
  • 93
  • 136
-1
JSch jsch = new JSch();
Session session = null;
try {
   session = jsch.getSession("user", "hostname", 22); // default
   UserInfo ui = new MyUserInfo();
   session.setUserInfo(ui);
   session.setPassword("password".getBytes());
   java.util.Properties config = new java.util.Properties();
   config.put("StrictHostKeyChecking", "no");
   session.setConfig(config);
   session.connect();
   Channel channel = session.openChannel("sftp");
   channel.connect();
   System.out.println("Connected");
} catch (JSchException e) {
   e.printStackTrace(System.out);
} catch (Exception e) {
   e.printStackTrace(System.out);
} finally {
   session.disconnect();
   System.out.println("Disconnected");
}
AsfK
  • 3,328
  • 4
  • 36
  • 73