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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36298394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 17:41:06  来源:igfitidea点击:

Java: InvalidAlgorithmParameterException Prime size must be multiple of 64

javasshjschjava-security

提问by Vaanz

I implemented a Java program that will connect and execute a command in a remote server using JSCH. The problem is that whenever I tried to connect to the server, I got the following exception:

我实现了一个 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)

I tried the solution of adding the Bouncy Castle provider in jre/lib and security.provider and it works. But I need to make it project dependent, so I tried to add Bouncy Castle in my build path and add manually the Bouncy Castle provider in my program. But after exporting it to jar, I am still receiving the exception.

我尝试了在 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();
    }
}
}

Here is my Server utilities that handles server connection:

这是我处理服务器连接的服务器实用程序:

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;
    }
}
}

While debugging, I find out that the error occurs when the printer service tries to connect to the server.

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

    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;
    }
}

I would also like to know if there is a way to make Bouncy Castle a light weight, since I need my jar to be < 2MB since I need to transfer it to a server, and I don't have a permission to transfer a file > 2MB.

我还想知道是否有办法让 Bouncy Castle 变得轻巧,因为我需要将 jar 小于 2MB,因为我需要将它传输到服务器,而且我没有传输文件的权限> 2MB。

Thank you for the help. This is my first post in stackoverflow, and I really love this community. Thanks.

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

采纳答案by Vaanz

I tried using a 2048 bit key that I generate in a server, still I am receiving those error. The solution that I found is to use a different SSH library and the one that works is Ganymed SSH-2, instead of JSch. Thank you for all the suggestions and comments.

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

Edited: In addition, this library is also light weight ~1MB.

编辑:此外,这个库也是轻量级的~1MB。

回答by Michael Wyraz

I solved a similar problem on oracle java 8 by switching to bouncycastle provider for ssl/tls:

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

  1. Added bouncycastle to my project

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.54</version>
    </dependency>
    
  2. Before I do any SSL stuff, I add the BouncyCastle provider as 1st provider to the list:

    Security.insertProviderAt(new BouncyCastleProvider(),1);
    
  1. 在我的项目中添加了 bouncycastle

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

    Security.insertProviderAt(new BouncyCastleProvider(),1);
    

This works with most stuff that uses sun's SSLSocketFactory, so it might also work with JSch.

这适用于大多数使用 sun 的 SSLSocketFactory 的东西,所以它也可能适用于 JSch。

回答by Salvador Valencia

I didn't have the benefit of switching to Ganymed, so I installed the "Bouncy Castle" libraries to replace the security on the JVM. For some reason the Java 8 JVM still does not allow for security keys to be larger than 1024 in length.

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

  1. Download the jar files from https://www.bouncycastle.org/latest_releases.html(look for jar files that start with 'bcprov-jdk')

  2. Place the jar files under $JAVA_HOME/jre/lib/ext

  3. Edit the java.security file located in $JAVA_HOME/jre/lib/security
  4. Scroll down past the middle of the file and you will find a numbered list of security providers (around 9 or 8). Place a comment for the line of the seecond provider (with a #)
  5. Replace the commented line with this:

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

  6. Restart what you must, and try again.

  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 个)。为 seecond 提供程序的行添加注释(带有 #)
  5. 将注释行替换为:

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

  6. 重新启动你必须做的,然后再试一次。

I'm baffled as to why we need to hack the JDK this way. It doesn't inspire a lot of confidence to anybody I mentioned it at work. But since there is poor documentation (or education) on anything relating to security we are treating it as a 'temporary' fix.

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

回答by jamjabi

I was getting this error

我收到这个错误

ERROR: Message form the remote server : Session.connect: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)

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

I was able to solve it by setting the client version as in this line

我能够通过在这一行中设置客户端版本来解决它

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

The default value that was causing the error is

导致错误的默认值是

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

回答by Prathyush

I too faced same issue and resolved it by degrading jar file from jsch-1.5.4 to jsch-1.5.0. Try changing jsch jar file and see which version is suitable for your code. The root cause of issue is due to some method in jsch jar file upgrade, expecting extra input parameter and it is missing in your code.

我也遇到了同样的问题,并通过将 jar 文件从 jsch-1.5.4 降级到 jsch-1.5.0 来解决它。尝试更改 jsch jar 文件,看看哪个版本适合您的代码。问题的根本原因是由于 jsch jar 文件升级中的某些方法,需要额外的输入参数并且它在您的代码中丢失。

回答by Beau Harder

My workaround was changing this registry key to allow 1024 bit DH keys in Windows 10 (2048 was/is the minimum bit size per https://docs.microsoft.com/en-us/security-updates/securityadvisories/2016/3174644)

我的解决方法是更改​​此注册表项以允许 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

回答by Impresi MLine

Add this line of code after you have the Session instance:

在您拥有 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);
      ...

The line to be added is: config.put("kex", "diffie-hellman-group1-sha1");

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

回答by Gurce

I was getting the same error with JGit's use of JSch. I tried a lot of suggestions in this thread to no avail.

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

But then recently, I noticed that if I used a slightly newer jre than I used before, the error went away.

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

Just for the record, I was using "jsch-0.1.55.jar" and the two jre's I tried were:

只是为了记录,我使用的是“jsch-0.1.55.jar”,我尝试过的两个 jre 是:

  • JRE 1.7.0_80 (experienced the exception)
  • JRE 1.8.0_191 (made the problem go away)
  • JRE 1.7.0_80(遇到异常)
  • JRE 1.8.0_191(使问题消失)

I can't say for sure whether it was merely the JRE upgrade that resolved the problem or the suggested tweaks from this thread that I made in addition.

我不能确定是否仅仅是 JRE 升级解决了问题,还是我另外提出的来自该线程的建议调整。

All the same, just wanted to share the experience in case it helps someone else.

尽管如此,只是想分享经验,以防它对其他人有所帮助。

回答by Aliuk

My solution to this problem was putting in the first line of my main method the following:

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

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

If you are using Spring you can add instead:

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

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