2

我正在尝试使用 JSCH jar 通过 Java 代码执行 SFTP。使用的 JSCH jar 版本是 0.1.55。我们的 pom.xml 文件中的条目是

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

我尝试连接的服务器是通过 AWS 提供的 VPC 接口端点服务公开的服务。尝试通过此 VPC 执行 SFTP 的客户端是 EC2 实例。

我遇到的错误是

com.jcraft.jsch.JSchException: Algorithm negotiation fail
at com.jcraft.jsch.Session.receive_kexinit(Session.java:590)
at com.jcraft.jsch.Session.connect(Session.java:320)

先前列出服务器和客户端上存在的不同算法的日志是

2019-03-14 08:50:54,501 INFO  [main]  Transporter - Remote version string: SSH-2.0-OpenSSH_7.4
2019-03-14 08:50:54,501 INFO  [main]  Transporter - Local version string: SSH-2.0-JSCH-0.1.54
2019-03-14 08:50:54,501 INFO  [main]  Transporter - CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256
2019-03-14 08:50:54,547 INFO  [main]  Transporter - CheckKexes: diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521
2019-03-14 08:50:54,590 INFO  [main]  Transporter - ecdh-sha2-nistp256 is not available.
2019-03-14 08:50:54,590 INFO  [main]  Transporter - ecdh-sha2-nistp384 is not available.
2019-03-14 08:50:54,590 INFO  [main]  Transporter - ecdh-sha2-nistp521 is not available.
2019-03-14 08:50:54,590 INFO  [main]  Transporter - CheckSignatures: ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
2019-03-14 08:50:54,592 INFO  [main]  Transporter - ecdsa-sha2-nistp256 is not available.
2019-03-14 08:50:54,593 INFO  [main]  Transporter - ecdsa-sha2-nistp384 is not available.
2019-03-14 08:50:54,593 INFO  [main]  Transporter - ecdsa-sha2-nistp521 is not available.
2019-03-14 08:50:54,593 INFO  [main]  Transporter - SSH_MSG_KEXINIT sent
2019-03-14 08:50:54,593 INFO  [main]  Transporter - SSH_MSG_KEXINIT received
2019-03-14 08:50:54,593 INFO  [main]  Transporter - kex: server: 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-group-exchange-sha1,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
2019-03-14 08:50:54,593 INFO  [main]  Transporter - kex: server: ecdsa-sha2-nistp256,ssh-ed25519
2019-03-14 08:50:54,593 INFO  [main]  Transporter - kex: server: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,arcfour
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: server: aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,arcfour
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: server: hmac-sha1,hmac-ripemd160
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: server: hmac-sha1,hmac-ripemd160
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: server: none,zlib@openssh.com
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: server: none,zlib@openssh.com
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: server: 
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: server: 
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: client: diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: client: ssh-rsa,ssh-dss
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
2019-03-14 08:50:54,594 INFO  [main]  Transporter - kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96
2019-03-14 08:50:54,595 INFO  [main]  Transporter - kex: client: none
2019-03-14 08:50:54,595 INFO  [main]  Transporter - kex: client: none
2019-03-14 08:50:54,595 INFO  [main]  Transporter - kex: client: 
2019-03-14 08:50:54,595 INFO  [main]  Transporter - kex: client: 

正如您在上面的日志中看到的,VPC 端点(服务器)上的 HostKeyAlgorithms 是:ecdsa-sha2-nistp256,ssh-ed25519,而 EC2 实例(客户端)上的 HostKeyAlgorithms 是:ssh-rsa,ssh-dss

由于服务器和客户端之间没有共同的算法来执行主机检查,因此由于算法协商失败而失败。

已尝试安装 JCE 无限强度策略文件的最建议解决方案,但未解决问题。我在 EC2 实例(客户端)上的$JAVA_HOME/jre/lib/security位置安装了 JCE 策略 jar 。

有关使用 JSCH 进行 SFTP 的代码以及在 JSCH jar 中进一步调试的详细信息。

我运行了命令

ssh -Q key

在 EC2 实例(客户端)环境中获取可用的主机密钥算法。(这样做是为了确认算法存在于环境中。)输出是

ssh-ed25519
ssh-ed25519-cert-v01@openssh.com
ssh-rsa
ssh-dss
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521
ssh-rsa-cert-v01@openssh.com
ssh-dss-cert-v01@openssh.com
ecdsa-sha2-nistp256-cert-v01@openssh.com
ecdsa-sha2-nistp384-cert-v01@openssh.com
ecdsa-sha2-nistp521-cert-v01@openssh.com

创建了一个 com.jcraft.jsch.Session 对象mSession,在调用mSession.connect(int timeOut)之前,我使用 mSession 对象的配置打印了 HostKeyAlgorithms

mSession.getConfig("server_host_key")

输出是

ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521

在 mSession.connect() 调用内部(此函数调用驻留在 JSCH jar 中),调用了this.send_kexinit()函数。在这个 send_kexinit() 函数中,下面的代码是设置最终 HostKeyAlgorithms 的代码。

String server_host_key = this.getConfig("server_host_key");
            String[] not_available_shks = this.checkSignatures(this.getConfig("CheckSignatures"));
            if (not_available_shks != null && not_available_shks.length > 0) {
                server_host_key = Util.diffString(server_host_key, not_available_shks);
                if (server_host_key == null) {
                    throw new JSchException("There are not any available sig algorithm.");
                }
            }

checkSignatures() 函数正在检查此列表中的算法列表this.getConfig("CheckSignatures")并检查它们是否存在。checkSignatures() 如下

private String[] checkSignatures(String sigs) {
        if (sigs != null && sigs.length() != 0) {
            if (JSch.getLogger().isEnabled(1)) {
                JSch.getLogger().log(1, "CheckSignatures: " + sigs);
            }

            Vector result = new Vector();
            String[] _sigs = Util.split(sigs, ",");

            for(int i = 0; i < _sigs.length; ++i) {
                try {
                    JSch var10000 = this.jsch;
                    Class c = Class.forName(JSch.getConfig(_sigs[i]));
                    Signature sig = (Signature)((Signature)c.newInstance());
                    sig.init();
                } catch (Exception var7) {
                    result.addElement(_sigs[i]);
                }
            }

            if (result.size() == 0) {
                return null;
            } else {
                String[] foo = new String[result.size()];
                System.arraycopy(result.toArray(), 0, foo, 0, result.size());
                if (JSch.getLogger().isEnabled(1)) {
                    for(int i = 0; i < foo.length; ++i) {
                        JSch.getLogger().log(1, foo[i] + " is not available.");
                    }
                }

                return foo;
            }
        } else {
            return null;
        }
    }

this.getConfig("CheckSignatures") 函数返回列表 ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521 并在此列表上调用上述函数时,找不到算法,因为它们打印在日志为

ecdsa-sha2-nistp256 is not available.
ecdsa-sha2-nistp384 is not available.
ecdsa-sha2-nistp521 is not available.

很明显 checkSignatures() 函数中的 try 块是调用失败的地方,因此它们已被添加到不可用列表中。因此,这 3 个算法从 HostKeyAlgorithms 列表中删除。所以名单

this.getConfig("server_host_key")

经过 checkSignatures() 方法后只有

ssh-rsa,ssh-dss

我无法理解为什么 try 块在 com.jcraft.jsch.JSch.java 文件中失败,上述 3 种算法已添加到 JSch 类的配置中。

config.put("CheckSignatures", "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521");
config.put("signature.dss", "com.jcraft.jsch.jce.SignatureDSA");
config.put("signature.rsa", "com.jcraft.jsch.jce.SignatureRSA");
config.put("keypairgen.dsa", "com.jcraft.jsch.jce.KeyPairGenDSA");
config.put("keypairgen.rsa", "com.jcraft.jsch.jce.KeyPairGenRSA");
config.put("keypairgen.ecdsa", "com.jcraft.jsch.jce.KeyPairGenECDSA");
config.put("ecdsa-sha2-nistp256", "com.jcraft.jsch.jce.SignatureECDSA256");
config.put("ecdsa-sha2-nistp384", "com.jcraft.jsch.jce.SignatureECDSA384");
config.put("ecdsa-sha2-nistp521", "com.jcraft.jsch.jce.SignatureECDSA521");
config.put("server_host_key", "ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521");

并且名为com.jcraft.jsch.jce.SignatureECDSA256com.jcraft.jsch.jce.SignatureECDSA384com.jcraft.jsch.jce.SignatureECDSA521的类存在于 jar 文件中各自的位置。

所以我不清楚为什么 checkSignatures() 函数中的 try 块会失败,即使这些类存在于 JSCH jar 中并且 JCE 无限强度策略文件已安装在$JAVA_HOME/jre/lib/security路径中适当地。(安装的策略文件适用于 JDK 1.8,因为我们使用的 JDK 版本是 1.8)

谁能帮我理解为什么这些算法(ecdsa-sha2-nistp256、ecdsa-sha2-nistp384、ecdsa-sha2-nistp521)(尤其是ecdsa-sha2-nistp256)不可用。(很明显,将 ecdsa-sha2-nistp256 添加到客户端可用的 HostKeyAlgorithms 列表中将为服务器和客户端协商提供一个通用算法。)

编辑:

当我们通过在 sshd_config 文件中添加以下行并重新启动 sshd 服务在服务器端添加密钥交换算法时,此问题得到解决。

KexAlgorithms ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1

添加算法ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521时,会出现以下错误

ecdsa-sha2-nistp256 is not available.
ecdsa-sha2-nistp384 is not available.
ecdsa-sha2-nistp521 is not available.

离开。仍在研究这些密钥交换算法和 HostKey 算法之间的关系。

4

0 回答 0