Java:InvalidAlgorithmParameterException Prime大小必须是64的倍数

时间:2016-03-30 02:08:50

标签: java ssh jsch java-security

我实现了一个Java程序,它将使用JSCH在远程服务器中连接并执行命令。问题是每当我尝试连接到服务器时,我都会遇到以下异常:

com.jcraft.jsch.JSchException: Session.connect: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 256 to 2048 (inclusive)

我尝试了在jre / lib和security.provider中添加Bouncy Castle提供程序的解决方案。但是我需要让它依赖于项目,所以我尝试在我的构建路径中添加Bouncy Castle并在我的程序中手动添加Bouncy Castle提供程序。但是在将它导出到jar后,我仍然收到例外。

package services;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.Security;
import java.util.Iterator;
import java.util.Properties;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class MainService {

public MainService() {
    Security.addProvider(new BouncyCastleProvider()); //Adding BouncyCastlePRovider in security
    // TODO Auto-generated constructor stub
    String report = "";
    StringBuilder sb = new StringBuilder();

    System.out.println("Running the monitoring...");
    System.out.println("Starting printer monitoring...");

    PrinterService ps = new PrinterService(); //A service that connects to the server and executes the commands
    System.out.println("Building report for printer");

    sb.append(ps.buildReport());

    System.out.println("Done building report for printer");
    System.out.println("Finish printer Monitoring...");
    report = sb.toString();
    writeToFile(report,"fai");
}

public static void main(String[] args) {
    // TODO Auto-generated method stub
    MainService msrv = new MainService();
}

public void writeToFile(String contents,String report_name){
    try {
        System.out.println("Writing to file...");
        PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(report_name+".html",false)));
        pw.println(contents);
        pw.close();
        System.out.println("Done writing...");
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

以下是处理服务器连接的服务器实用程序:

package utilities;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Properties;

import javax.swing.JOptionPane;

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

import entity.Server;

public class ServerUtil {

public ServerUtil() {
    // TODO Auto-generated constructor stub
}

public static Session createSession(Server srv){
    JSch js = new JSch();
    try {
        Session s = js.getSession(srv.getUser().getUsername(), srv.getAddress(), 22);
        s.setPassword(srv.getUser().getPassword());
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        config.put("PreferredAuthentications", "password");
        s.setConfig(config);
        s.connect();
        return s;
    } catch (JSchException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    }
}

public static ArrayList<String> executeCommands(Session s, String commands){
    ArrayList<String> result = new ArrayList<String>();
    try {
        System.out.println("Creating channel...");
        ChannelExec channel = (ChannelExec) s.openChannel("exec");
        System.out.println("Channel created.");
        System.out.println("Setting commands...");
        channel.setCommand(commands);
        System.out.println("Commands set.");
        System.out.println("Connecting to channel...");
        channel.connect();
        System.out.println("Channel connected.");

        System.out.println("Retrieving output...");
        BufferedReader reader = new BufferedReader(new InputStreamReader(channel.getInputStream()));
        String line;
        while((line = reader.readLine()) != null){
                result.add(line);
        }
        System.out.println("Output retrieved.");
        channel.disconnect();
        System.out.println("Returning result...");
        return result;
    } catch (JSchException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return result;
    }catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return result;
    }
}
}

在调试时,我发现当打印机服务尝试连接到服务器时会发生错误。

    package services;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.StringTokenizer;

import com.jcraft.jsch.Session;

import entity.Server;
import utilities.DatabaseUtil;
import utilities.ServerUtil;

public class PrinterService {

    private ArrayList<String> server_names;
    private ArrayList<ArrayList<String>> result_server;

    public PrinterService() {
        // TODO Auto-generated constructor stub
        executePrinterMonitoring();
    }

    //Connect to the printer server and process printer monitoring
    public void executePrinterMonitoring(){
        Iterator<Server> it_s = DatabaseUtil.getServers("PRINTER").iterator();
        server_names = new ArrayList<String>();
        result_server = new ArrayList<ArrayList<String>>();
        while(it_s.hasNext()){
            Server svr = it_s.next();
            System.out.println("***********START PRINTER SERVER***********");
            String commands = "lpstat -t | sed '/READY/d'; lpstat -W | sed '/READY/d'";
            Session connect = ServerUtil.createSession(svr);
            StringTokenizer tokenize = new StringTokenizer(commands, ";");
            ArrayList<String> res;
            ArrayList<ArrayList<String>> res2 = new ArrayList<ArrayList<String>>();
            System.out.println("Executing commands...");
            while(tokenize.hasMoreTokens()){
                String comm = tokenize.nextToken().trim();
                res = ServerUtil.executeCommands(connect, comm);
                res2.add(res);
            }
            System.out.println("Done executing commands...");
            System.out.println("Processing results...");
            processPMonitoring(res2,svr.getName());
            connect.disconnect();
            System.out.println("***********END PRINTER SERVER***********");
        }
   }

    //Get the current date, date - 1, and date - 2
    public String getDate(Calendar cal){
        String mon;
        String dy;
        String dy2;
        String dy3;
        String yr;
        int month = cal.get(Calendar.MONTH)+1;
        int day = cal.get(Calendar.DATE);
        int year = cal.get(Calendar.YEAR);
        if(month < 10)
             mon = "0"+month;
        else
             mon = ""+month;
        if(day < 10){
            dy = "0"+day;
        }
        else{
            dy = ""+day;
        }
        yr = (year+"").substring(2, 4);
        String date =  mon+ "/"+dy+"/"+yr;

        return date;
    }

    //Split and process the result from the server.
public void processPMonitoring(ArrayList<ArrayList<String>> s,String servername){

        Iterator<String> res1 = s.get(0).iterator();
        Iterator<String> res2 = s.get(1).iterator();
        ArrayList<String> as = new ArrayList<String>();
        ArrayList<String> fres = new ArrayList<String>();

        Calendar cal = Calendar.getInstance();
        String date1 = getDate(cal);
        cal.add(Calendar.DATE, -1);
        String date2 = getDate(cal);
        cal.add(Calendar.DATE, -1);
        String date3 = getDate(cal);
        int header = 1;

        System.out.println("Checking server:"+servername);
        System.out.println("Getting queued results...");
        while(res1.hasNext()){
            if(header <= 3){
                //as.add(res1.next());
                header++;
            }
            else{
                String curr = res1.next();
                if(curr.contains("@")){
                    if(curr.contains("STDIN")){
                        String f4 = "";
                        String f5 = "";
                        if(res1.hasNext())
                            f4 = res1.next();
                        if(res1.hasNext())
                            f5 = res1.next();

                        if(f4.contains(date1)){
                            as.add(curr);
                        }
                        else if(f4.contains(date2)){
                            as.add(curr);
                        }
                        else if(f4.contains(date3)){
                            as.add(curr);
                        }
                    }
                }
                else{
                    String f1 = curr;
                    String f2 = "";
                    String f3 = "";
                    if(res1.hasNext())
                        f2 = res1.next();
                    if(res1.hasNext())
                        f3 = res1.next();
                    if(f2.contains(date1)){
                        as.add(f1);
                    }
                    else if(f2.contains(date2)){
                        as.add(f1);
                    }
                    else if(f2.contains(date3)){
                        as.add(f1 + " - 3 DAYS OLD!");
                    }
                }
            }
        }

        System.out.println("Done queued results...");
        Iterator<String> g = as.iterator();
        boolean flag = true;
        String cl = "";
        String std = "";
        header = 1;
        System.out.println("Processing queued results...");
        while(res2.hasNext() && g.hasNext()){
            if(header <=2){
                fres.add(res2.next());
                header++;
            }
            else{
                String curr = res2.next();
                if(curr.contains("@")){
                        fres.add(curr);
                        continue;
                }
                if(flag){
                    cl = g.next();
                    if(cl.contains("@") && cl.contains("STDIN")){
                        continue;
                    }
                    int first_st = cl.indexOf("STDIN");
                    int last_ind = 0;
                    for(last_ind = first_st+1;;last_ind++){
                        //System.out.println("Value of CL:"+cl);
                        //System.out.println("Checking for spaces");
                        //System.out.println("STD CURRENT CHAR:"+cl.charAt(last_ind));
                        if(cl.charAt(last_ind) == ' '){
                            break;
                        }
                    }
                    std = cl.substring(first_st, last_ind);

                    flag = false;

                    if(fres.get(fres.size()-1).contains(std)){
                        flag = true;
                        continue;
                    }

                }
                if(curr.contains(std)){
                    fres.add(curr);
                    flag = true;
                }
            }
        }

        System.out.println("Done processing queued results...");
        System.out.println("Post-process queued results...");
        int size = fres.size();
        boolean down = false;
        for(int i=0;i<size;i++){
            if(fres.get(i).contains("@") && fres.get(i).contains("DOWN")){
                down = true;
                fres.remove(i);
                i--;
                size--;
                continue;
            }
            if(down){
                if(fres.get(i).contains("@") && !fres.get(i).contains("DOWN")){
                    down = false;
                    continue;
                }
                fres.remove(i);
                i--;
                size--;
            }
        }
        System.out.println("Done post-processing queued results...");
        //Post-process
        server_names.add(servername);
        result_server.add(fres);
        //fres.add(0,servername);
        //writeToFile(fres,3);
    }

    public String buildReport(){
        String report = "";
        StringBuilder sb = new StringBuilder();
        Timestamp ts = new Timestamp(new Date().getTime());
        sb.append("<table style=\"border:1px solid black; text-align:center;\" rules=\"all\">");
        sb.append("<h1 style=\"margin:0px 0px 0px 50px\">Printer Monitoring as of "+ts.toString()+"</h1>");
        sb.append("<tr style=\"background-color: seagreen\">"
                + "<th style=\"padding: 6px\">SERVER</th>"
                + "<th style=\"padding: 6px\">QUEUE</th>"
                + "<th style=\"padding: 6px\">DEV</th>"
                + "<th style=\"padding: 6px\">STATUS</th>"
                + "<th style=\"padding: 6px\">JOB FILES</th>"
                + "<th style=\"padding: 6px\">USER</th>"
                + "<th style=\"padding: 6px\">PP</th>"
                + "<th style=\"padding: 6px\">%</th>"
                + "<th style=\"padding: 6px\">BLKS</th>"
                + "<th style=\"padding: 6px\">CP</th>"
                + "<th style=\"padding: 6px\">RNK</th>"
                + "</tr>");
        int counter = 0;
        Iterator<String> it_s = server_names.iterator();
        while(it_s.hasNext()){
            sb.append("<tr style=\"background-color: green\"><td style=\"padding: 6px\"><b>"+it_s.next().toUpperCase()+"</b></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>");
            Iterator<String> it_res = result_server.get(counter).iterator();
            if(result_server.get(counter).isEmpty()){
                sb.append("<tr><td></td><td style=\"padding: 6px\"><h5>CLEAN</h5></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>");
            }
            else if(result_server.get(counter).size() == 2){
                sb.append("<tr><td></td><td style=\"padding: 6px\"><h5>CLEAN</h5></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>");
            }
            else{
                while(it_res.hasNext()){
                    String res = it_res.next();
                    if(!res.contains("Dev") && !res.contains("----")){
                        StringTokenizer tok = new StringTokenizer(res," ");
                        sb.append("<tr>");

                        if(tok.countTokens() == 11){
                            sb.append("<td style=\"padding: 6px\"></td>");
                            for(int x=0;x<10;x++){
                                if(x == 3){
                                    sb.append("<td style=\"padding: 6px\">"+tok.nextToken()+" "+tok.nextToken()+"</td>");
                                }
                                else{
                                    sb.append("<td style=\"padding: 6px\">"+tok.nextToken()+"</td>");
                                }
                            }
                        }
                        else{
                            sb.append("<td style=\"padding: 6px\"></td>");
                            sb.append("<td style=\"padding: 6px\"></td>");
                            sb.append("<td style=\"padding: 6px\"></td>");
                            sb.append("<td style=\"padding: 6px\">"+tok.nextToken()+"</td>");
                            sb.append("<td style=\"padding: 6px\">"+tok.nextToken()+" "+tok.nextToken()+"</td>");
                            sb.append("<td style=\"padding: 6px\">"+tok.nextToken()+"</td>");
                            sb.append("<td style=\"padding: 6px\"></td>");
                            sb.append("<td style=\"padding: 6px\"></td>");
                            sb.append("<td style=\"padding: 6px\">"+tok.nextToken()+"</td>");
                            sb.append("<td style=\"padding: 6px\">"+tok.nextToken()+"</td>");
                            sb.append("<td style=\"padding: 6px\">"+tok.nextToken()+"</td>");
                        }
                        sb.append("</tr>");
                    }
                }
            }
            counter++;
        }
        sb.append("</table>");
        sb.append("</br></br>");
        report = sb.toString();
        return report;
    }
}

我还想知道是否有办法让Bouncy Castle重量轻,因为我需要我的罐子。 2MB,因为我需要将其转移到服务器,而我没有权限转移文件&gt; 2MB。

感谢您的帮助。这是我在stackoverflow中的第一篇文章,我真的很喜欢这个社区。感谢。

9 个答案:

答案 0 :(得分:6)

我没有切换到Ganymed的好处,所以我安装了“Bouncy Castle”库来取代JVM上的安全性。出于某种原因,Java 8 JVM仍然不允许安全密钥长度大于1024。

  1. https://www.bouncycastle.org/latest_releases.html下载jar文件(查找以'bcprov-jdk'开头的jar文件)

  2. 将jar文件放在$ JAVA_HOME / jre / lib / ext

  3. 编辑$ JAVA_HOME / jre / lib / security中的java.security文件
  4. 向下滚动到文件中间,您将找到一个安全提供程序的编号列表(大约9或8)。为second提供者的行(带#)
  5. 发表评论
  6. 用以下代码替换注释行:

    security.provider.2 = org.bouncycastle.jce.provider.BouncyCastleProvider

  7. 重新启动您必须的内容,然后重试。

  8. 我很困惑为什么我们需要以这种方式破解JDK。对于我在工作中提到它的任何人来说,它并没有激发很大的信心。但由于与安全相关的任何文件(或教育)都很差,我们将其视为“临时”修复。

答案 1 :(得分:2)

我通过切换到ssl / tls的bouncycastle提供程序解决了oracle java 8上的类似问题:

  1. 在我的项目中添加了bouncycastle

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.54</version>
    </dependency>
    
  2. 在我做任何SSL之前,我将BouncyCastle提供商作为第一个提供者添加到列表中:

    Security.insertProviderAt(new BouncyCastleProvider(),1);
    
  3. 这适用于大多数使用sun的SSLSocketFactory的东西,因此它也适用于JSch。

答案 2 :(得分:1)

我尝试使用我在服务器中生成的2048位密钥,但仍然收到这些错误。我找到的解决方案是使用不同的SSH库,有效的是Ganymed SSH-2,而不是JSch。感谢您提出的所有建议和意见。

编辑:此外,这个库也重量轻〜1MB。

答案 3 :(得分:1)

我对此问题的解决方案是在我的主要方法的第一行中添加以下内容:

public static void main(String[] args) {
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    ...
}

如果您使用的是Spring,则可以添加:

@Configuration
public class AppConfig {
    @PostConstruct
    public void init(){
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }
}

答案 4 :(得分:0)

我也面临同样的问题,并通过将jar文件从jsch-1.5.4降级到jsch-1.5.0来解决了这个问题。尝试更改jsch jar文件,然后查看哪个版本适合您的代码。问题的根本原因是由于jsch jar文件升级中的某种方法,需要额外的输入参数,因此代码中缺少该参数。

答案 5 :(得分:0)

我的解决方法是更改​​此注册表项,以允许Windows 10中使用1024位DH密钥(2048是/是每个https://docs.microsoft.com/en-us/security-updates/securityadvisories/2016/3174644的最小位大小)

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman]
"ServerMinKeyBitLength"=dword:00000400

答案 6 :(得分:0)

我在JGit使用JSch时遇到了同样的错误。我在此线程中尝试了很多建议,但无济于事。

但是最近,我注意到,如果我使用的jre比以前使用的要新,错误就会消失。

就记录而言,我使用的是“ jsch-0.1.55.jar”,而我尝试使用的两个jre是:

  • JRE 1.7.0_80(遇到异常)
  • JRE 1.8.0_191(使问题消失了)

我不能确定是解决问题的仅仅是JRE升级,还是我对此线程所做的建议调整。

都一样,只是想分享经验,以防其他人受益。

答案 7 :(得分:-1)

我收到此错误

  

错误:来自远程服务器的消息:Session.connect:java.security.InvalidAlgorithmParameterException:Prime大小必须是64的倍数,并且只能在512到1024之间(包括)

我能够通过设置此行中的客户端版本来解决它

session.setClientVersion("SSH-2.0-OpenSSH_2.5.3");

导致错误的默认值是

session.setClientVersion("SSH-2.0-JSCH-0.1.54");

答案 8 :(得分:-1)

拥有Session实例后,添加以下代码行:

public static Session createSession(Server srv){
   JSch js = new JSch();
   try {
      Session s = js.getSession(srv.getUser().getUsername(), srv.getAddress(), 22);
      s.setPassword(srv.getUser().getPassword());
      Properties config = new Properties();
      config.put("StrictHostKeyChecking", "no");
      config.put("PreferredAuthentications", "password");
      config.put("kex", "diffie-hellman-group1-sha1");
      s.setConfig(config);
      ...

要添加的行是: config.put(“ kex”,“ diffie-hellman-group1-sha1”);