This article shows how to do file transfer from a remote server to the local system and vice versa, using SSH File Transfer Protocol (SFTP) in Java.

P.S Tested with JSch 0.1.55

1. JSch Dependency

pom.xml

  <dependency>
      <groupId>com.jcraft</groupId>
      <artifactId>jsch</artifactId>
      <version>0.1.55</version>
  </dependency>

2. File Transfer – JSch Examples

2.1 In JSch, we can use put and get to do file transfer between servers.

We use put to transfer files from a local system to the remote server.

channelSftp.put(localFile, remoteFile);

We use get to download files from a remote server to the local system.

channelSftp.get(remoteFile, localFile)

2.2 Password authentication.

  JSch jsch = new JSch();
  jsch.setKnownHosts("/home/favtuts/.ssh/known_hosts");
  jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);

  jschSession.setPassword(PASSWORD);

2.3 Public and private keys authentication, read this Use Public Key Authentication with SSH

  • Local private key – /home/favtuts/.ssh/id_rsa
  • Remote public key – ~/.ssh/authorized_keys
  JSch jsch = new JSch();
  jsch.setKnownHosts("/home/favtuts/.ssh/known_hosts");
  jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);

  jsch.addIdentity("/home/favtuts/.ssh/id_rsa");

2.4 Review this complete JSch example to transfer a file from the local system to a remote server 1.2.3.4, authenticate using an SSH password.

SFTPFileTransfer.java

package com.favtuts.io.howto;

import com.jcraft.jsch.*;

public class SFTPFileTransfer {

    private static final String REMOTE_HOST = "1.2.3.4";
    private static final String USERNAME = "";
    private static final String PASSWORD = "";
    private static final int REMOTE_PORT = 22;
    private static final int SESSION_TIMEOUT = 10000;
    private static final int CHANNEL_TIMEOUT = 5000;

    public static void main(String[] args) {

        String localFile = "/home/favtuts/local/random.txt";
        String remoteFile = "/home/favtuts/remote/afile.txt";

        Session jschSession = null;

        try {

            JSch jsch = new JSch();
            jsch.setKnownHosts("/home/favtuts/.ssh/known_hosts");
            jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);

            // authenticate using private key
            // jsch.addIdentity("/home/favtuts/.ssh/id_rsa");

            // authenticate using password
            jschSession.setPassword(PASSWORD);

            // 10 seconds session timeout
            jschSession.connect(SESSION_TIMEOUT);

            Channel sftp = jschSession.openChannel("sftp");

            // 5 seconds timeout
            sftp.connect(CHANNEL_TIMEOUT);

            ChannelSftp channelSftp = (ChannelSftp) sftp;

            // transfer file from local to remote server
            channelSftp.put(localFile, remoteFile);

            // download file from remote server to local
            // channelSftp.get(remoteFile, localFile);

            channelSftp.exit();

        } catch (JSchException | SftpException e) {

            e.printStackTrace();

        } finally {
            if (jschSession != null) {
                jschSession.disconnect();
            }
        }

        System.out.println("Done");
    }

}

3. JSch Exceptions

Some common exceptions.

3.1 For UnknownHostKey exception, add the remote IP address into the known_hosts file.

Run the above program, and it throws UnknownHostKey?

com.jcraft.jsch.JSchException: UnknownHostKey: 1.1.1.1. RSA key fingerprint is ::::
	at com.jcraft.jsch.Session.checkHost(Session.java:805)
	at com.jcraft.jsch.Session.connect(Session.java:345)
	at com.jcraft.jsch.Session.connect(Session.java:183)
	at com.favtuts.io.howto.SFTPFileTransfer.initJsch(SFTPFileTransfer.java:29)
	at com.favtuts.io.howto.SFTPFileTransfer.uploadFileUsingJsch(SFTPFileTransfer.java:35)
	at com.favtuts.io.howto.SFTPFileTransfer.main(SFTPFileTransfer.java:16)

To solve it, we can use ssh-keyscan to add the remote IP address or hostname into the ~/.ssh/known_hosts

ssh-keyscan -t rsa <HOST_NAME> >> ~/.ssh/known_hosts
ssh-keyscan -t rsa <IP_ADDRESS_OF_HOST_NAME> >> ~/.ssh/known_hosts

For example,

$ ssh-keyscan -t rsa 1.2.3.4 >> ~/.ssh/known_hosts
# 1.1.1.1:22 SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u7

3.2 For invalid privatekey, convert the private key to another format.

This Java example tries to use JSch to transfer a file from the local folder to a remote server using public and private keys, instead of a password.

            // private key location
            jsch.addIdentity("/home/favtuts/.ssh/id_rsa");

It may throws the invalid privatekey exception.

com.jcraft.jsch.JSchException: invalid privatekey: [B@1324409e
	at com.jcraft.jsch.KeyPair.load(KeyPair.java:664)
	at com.jcraft.jsch.KeyPair.load(KeyPair.java:561)
	at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40)
	at com.jcraft.jsch.JSch.addIdentity(JSch.java:406)
	at com.jcraft.jsch.JSch.addIdentity(JSch.java:366)
	at com.favtuts.io.howto.SFTPFileTransfer.main(SFTPFileTransfer.java:31)

Check the private key, and it looks something like:

$ cat /home/favtuts/.ssh/id_rsa

$ cat /home/favtuts/.ssh/id_rsa

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC...
...
...
...MAECAwQF
-----END OPENSSH PRIVATE KEY-----

Solution

The Jsch seems not to support the above private key format, to solve it, we can use ssh-keygen to convert the private key format to the RSA or pem mode, and the above program works again.

$ ssh-keygen -p -f ~/.ssh/id_rsa -m pem

Recheck the private key content, it should starts with BEGIN RSA.

$ cat /home/mkyong/.ssh/id_rsa

-----BEGIN RSA PRIVATE KEY-----
MIIG4wIBAAK...
...
...
...E428GBDI4
-----END RSA PRIVATE KEY-----

3.3 For Auth fail, make sure the provided password is correct.

com.jcraft.jsch.JSchException: Auth fail
	at com.jcraft.jsch.Session.connect(Session.java:519)
	at com.favtuts.io.howto.SFTPFileTransfer.main(SFTPFileTransfer.java:34)

Download Source Code

$ git clone https://github.com/favtuts/java-core-tutorials-examples

$ cd java-io/howto

References

Leave a Reply

Your email address will not be published. Required fields are marked *