java - 签名长度不正确 : got 127 but was expecting 128

标签 java security jsch

java 1.8 升级后我遇到了一个奇怪的问题。我在我们的一个实用程序中使用 jsch-0.1.54.jar 从各个地方下载文件。这个特殊的实用程序已经使用了将近 4-5 年,没有任何问题(当时是 jsch-0.1.48)。当时环境是java 1.6。最近我们升级到 java 1.8,因此我们升级了这个特定的实用程序。现在我们遇到一个奇怪的问题,它偶尔会出现,而且大多数时候文件下载都是完美的。

错误日志

INFO: SSH_MSG_KEXDH_INIT sent
INFO: expecting SSH_MSG_KEXDH_REPLY
INFO: Disconnecting from SRV2000 port 22
2016-10-28 08:42:18:0576 ERROR  [main] net.AerisAbstractMethod - Failed to open connection 
com.jcraft.jsch.JSchException: Session.connect: java.security.SignatureException: Signature length not correct: got 127 but was expecting 128
    at com.jcraft.jsch.Session.connect(Session.java:565)
    at com.jcraft.jsch.Session.connect(Session.java:183)
    at com.aeris.net.AerisSFTPMethod.connectToServer(AerisSFTPMethod.java:65)
    at com.aeris.net.AerisAbstractMethod.getListOfFiles(AerisAbstractMethod.java:143)
    at com.aeris.worker.AerisUploaderDownloader.performUploadDownloadListing(AerisUploaderDownloader.java:112)
    at com.aeris.main.AerisCommonSftpUtility.main(AerisCommonSftpUtility.java:102)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.simontuffs.onejar.Boot.run(Boot.java:340)
    at com.simontuffs.onejar.Boot.main(Boot.java:166)

成功日志:(大部分情况下是成功的)

INFO: SSH_MSG_KEXDH_INIT sent
INFO: expecting SSH_MSG_KEXDH_REPLY
INFO: ssh_rsa_verify: signature true
WARN: Permanently added 'SRV2000' (RSA) to the list of known hosts.
INFO: SSH_MSG_NEWKEYS sent
INFO: SSH_MSG_NEWKEYS received
INFO: SSH_MSG_SERVICE_REQUEST sent
INFO: SSH_MSG_SERVICE_ACCEPT received
INFO: Authentications that can continue: publickey,password,keyboard-interactive
INFO: Next authentication method: publickey
INFO: Authentication succeeded (publickey).
2016-10-28 08:36:48:0794 INFO   [main] net.AerisAbstractMethod - Session connected to server
2016-10-28 08:36:48:0794 INFO   [main] net.AerisAbstractMethod - Opening SFTP channel..
2016-10-28 08:36:48:0810 INFO   [main] net.AerisAbstractMethod - Connecting to server through channel.
2016-10-28 08:36:48:0857 INFO   [main] net.AerisAbstractMethod - Connection successful.
2016-10-28 08:36:48:0857 INFO   [main] net.AerisAbstractMethod - Changing to directory:C:/interfaces/ib/wf/work
2016-10-28 08:36:48:0888 INFO   [main] net.AerisAbstractMethod - Start file Listing of the remote directory:C:/interfaces/ib/wf/work

       0 Oct 28, 2016 04:15 ./
       0 Oct 28, 2016 04:15 ../

我与 Vandyke(sftp 软件提供商)进行了全面分析,但最终没有发现任何错误。我也尝试使用不同的工具进行 sftp,但我没有收到任何错误。以下是连接 SFTP 服务器的代码片段。任何人都可以帮助解决这个问题吗?

protected void connectToServer() throws AerisConnectionException {
        JSch jSch =(JSch)this.client;
        try {

            session = jSch.getSession(config.getUsername(), config.getRemoteserver(), config.getPort());
            LOGGER.info("Creating SSH Session using Username:"+config.getUsername()+ " Server :" +config.getRemoteserver()+ " at PORT:"+config.getPort());
            if(config.getAuth().equalsIgnoreCase("PASSWD")||config.getAuth().equalsIgnoreCase("KEYPASS")){
                LOGGER.info("Setting password ...");
                session.setPassword(config.getPassword());
            }

            Properties jShconfig = new Properties();            
            jShconfig.put("StrictHostKeyChecking", "no");
            jShconfig.put("PreferredAuthentications", 
                      "publickey,password,keyboard-interactive");
            jShconfig.put("LogLevel", "VERBOSE");


            LOGGER.info("Setting timeout to "+config.getTimeOut());
            session.setTimeout(config.getTimeOut()*1000);
            session.setConfig(jShconfig);           

            session.connect();
            LOGGER.info("Session connected to server");
            this.connected=true;

        } catch (JSchException e) {
            LOGGER.error("Failed to open connection ",e);
            throw new AerisConnectionException("Failed to open connection.");
        }

    }

最佳答案

虽然有堆栈跟踪来确认会很好,我敢打赌服务器正在使用 RSA“主机” key 进行身份验证,并且在极少数情况下会错误地“修剪”前导零。

由 PKCS#1 定义的 RSA 签名值(以及加密值),SSH uses (与包括 SSL 在内的许多其他事物一样),需要被编码为固定长度“k”的八位字节字符串,等于编码模数所需的长度,或者非正式地“与模数相同的大小”。然而,由于基础数学值是一个大的非负(又名无符号)整数,特别是 modexp(s,d,n),历史上一些实现省略了前导零八位字节——当将值 视为时有效的省略一个整数——导致编码值有时比它应该的短。

RSA 签名(或加密)值实际上是 (1,n) 中的均匀随机数。因此,当服务器使用的 RSA key 具有像此处的 1024 这样的“圆形二进制”大小时,这种修剪将随机发生大约 200 次中的 1 次,如果修剪为带符号的数字,则为 400 次。

我不知道,但在测试中我确认 (Oracle) Java 6 确实接受 Signature 这样的“短”值输入 RSA或此处实际使用的 SHA1withRSA ,两者都暗示 PKCS1-v1_5 方案,但 Java 7 和 8 抛出您看到的异常。 OTOH OpenSSH 和 PuTTY(也被 WinSCP 和 FileZilla 使用)确实接受“短”值,同时始终发送正确的长度值;这种 Postelian 行为可能会使检测同伴何时以这种方式行为不端变得更加困难。 (注意:我检查了 OpenSSH 5.5 和 7.3,这是我手边最旧和最新的版本,但只有当前的 PuTTY 0.67,因为这是我保持在线的全部。)

您可以尝试将服务器软件实现者指向已发布的标准,但这可能没有任何好处。你可以要求 jcraft 对此进行特殊处理;他们在 mpint/ASN.1 的 DSA 和 ECDSA 案例中已经有了逻辑,我可能会认为这同样丑陋。 或者如果服务器有另一个(可用的) key ,请求通过配置"server_host_key"不包括 ssh-rsa -- 最简单的就是获取现有/默认列表,拆分,删除 "ssh-rsa" (并检查不为空)并重新加入,而不是通过列出今天的特定算法可能混淆您的用户和/或(共同)维护者。

关于java - 签名长度不正确 : got 127 but was expecting 128,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40339058/

相关文章:

java - 流程执行Java JSsh

java8 - 使用 ChannelSftp 模式匹配选择最后修改的文件

java - 如何使用 JSch 进行原子 SFTP 文件传输,以便在写入过程完成之前无法访问文件?

java - 如何检测时间戳是否位于其他两个时间戳之间?

java - 复制的 Netbeans IDE Maven Web 项目无法编译

java - Mockito/JMockit 和 Hamcrest 匹配器 : How to verify Lists/Collections?

jquery - 阻止对 API 的外部调用(安全)

java - 将非 Maven 项目转换为 Maven

ios - iOS安全异常(exception)(-9813)仅来自翠鸟库的调用

android - ObjectOutputStream:这安全吗?