Java – 通过Runtime执行OpenSSL命令时出错

huangapple go评论57阅读模式
英文:

Java - Error in executing OpenSSL command thorugh Runtime

问题

public void executeCmd() throws IOException {
    Runtime rt = Runtime.getRuntime();
    String[] commands = new String[]{"openssl", "rsa", "-noout", "-modules", "-in", "myPathToKeyFile", "|", "openssl", "sha256"};
    
    Process proc = rt.exec(commands);
    BufferedReader stdInKey = new BufferedReader(new InputStreamReader(proc.getInputStream()));

    String s = null;
    
    while ((s = stdInKey.readLine()) != null) {
        System.out.println(s);
    }
}
Exception in thread "main" java.io.IOException: Cannot run program "openssl": CreateProcess error=2, The system cannot find the file specified
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
	at java.lang.Runtime.exec(Runtime.java:620)
	at java.lang.Runtime.exec(Runtime.java:485)
	at com.renault.vnext.business.impl.CmdRunner.executeCmd(CmdRunner.java:22)
	at com.renault.vnext.business.impl.CmdRunner.main(CmdRunner.java:10)
Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified
	at java.lang.ProcessImpl.create(Native Method)
	at java.lang.ProcessImpl.<init>(ProcessImpl.java:444)
	at java.lang.ProcessImpl.start(ProcessImpl.java:140)
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
	... 4 more

Note: I have set up to the "bin" folder in the path variable.

I am able to run the command in the cmd and get the output. My requirement is to get the stdin value from the command output.

英文:

I have the following code to execute Openssl command and read the ouptut produced by the command through Java Runtime

public void executeCmd() throws IOException {
		Runtime rt = Runtime.getRuntime();
		String[] commands = new String[]{&quot;openssl&quot;, &quot;rsa&quot;, &quot;-noout&quot;, &quot;-modules&quot;, &quot;-in&quot;, &quot;myPathToKeyFile&quot;, &quot;|&quot;, &quot;openssl&quot;, &quot;sha256&quot;};
		
		Process proc = rt.exec(commands);
		BufferedReader stdInKey = new BufferedReader(new InputStreamReader(proc.getInputStream()));

		 String s = null;
		
		while ((s = stdInKey.readLine()) != null) {
		    System.out.println(s);
		}
		
	}

When i run the command through Cmd, it is working and I am able to see the output

But When I run through this code, I am getting following error :

Exception in thread &quot;main&quot; java.io.IOException: Cannot run program &quot;openssl&quot;: CreateProcess error=2, The system cannot find the file specified
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
	at java.lang.Runtime.exec(Runtime.java:620)
	at java.lang.Runtime.exec(Runtime.java:485)
	at com.renault.vnext.business.impl.CmdRunner.executeCmd(CmdRunner.java:22)
	at com.renault.vnext.business.impl.CmdRunner.main(CmdRunner.java:10)
Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified
	at java.lang.ProcessImpl.create(Native Method)
	at java.lang.ProcessImpl.&lt;init&gt;(ProcessImpl.java:444)
	at java.lang.ProcessImpl.start(ProcessImpl.java:140)
	at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
	... 4 more

Note : I have set upto bin folder in the path variable

I am able to run the command in cmd and get the output. My requirement is to get the stdin value from the command ouptut

Java – 通过Runtime执行OpenSSL命令时出错

Much appreciating your help!

答案1

得分: 2

首先,显然您的PATH环境变量中没有任何目录中的openssl[.exe]。要么更改您的PATH以包括包含openssl可执行文件的目录,要么更改您的代码以指定openssl可执行文件的完整路径(这样它就不需要使用PATH)。如果在Windows上,注意您可以在单个进程中更改PATH,或者在注册表中全局更改;在后一种情况下,您需要重新创建使用PATH的任何进程,例如您的“命令”窗口、终端、shell、powershell或IDE。重复链接https://stackoverflow.com/questions/28028684/java-exec-cant-run-program-error-2 和 https://stackoverflow.com/questions/19621838/createprocess-error-2-the-system-cannot-find-the-file-specified

其次,您拼写错误了-modulus

第三,将类似于"&amp;quot;|&amp;quot;"等的重定向作为参数传递给openssl是行不通的。当您在Unix的shell中输入openssl rsa ... | openssl sha256,或者在Windows的命令提示符中输入时,这并不会将| openssl sha256传递给第一个openssl;相反,它会运行两个不同的进程,并将第一个进程的输出重定向到一个管道,然后将第二个进程的输入从该管道读取。Runtime.exec()不是命令处理器,无法执行此操作。您可以:

  • 仅运行openssl rsa部分,在Java代码中读取输出,并在Java中进行该输出的SHA256处理。
  • 运行命令解释器,并告诉它执行复合命令openssl rsa ... | openssl sha256(作为一个字符串)。在Unix上使用适当的shell - 这可能因您的系统而异,但/bin/sh -c是常见的。在Windows上使用cmd.exe /c

另外,如果您有或获得了BouncyCastle库,它们可以读取与openssl rsa相同的文件,并且可以在Java中直接提取模数、格式化并进行哈希处理,而无需使用openssl。但您没有询问这个,所以在Stack上这不是一个答案。

英文:

First, you apparently don't have openssl[.exe] in any of the directories in your PATH environment variable. Either change your PATH to include the directory containing the openssl executable, or change your code to specify the full pathname of the openssl executable (so it doesn't need to use PATH). If on Windows, note you can change PATH in a single process, or globally in the registry; in the latter case, you need to re-create any process using PATH such as your 'command' window, terminal, shell, powershell, or IDE. Dupe https://stackoverflow.com/questions/28028684/java-exec-cant-run-program-error-2 and https://stackoverflow.com/questions/19621838/createprocess-error-2-the-system-cannot-find-the-file-specified .

Second, you misspelled -modulus.

Third, passing a redirection like &quot;|&quot;,etc as arguments to openssl won't work. When you type openssl rsa ... | openssl sha256 to a shell in Unix or the command prompt in Windows, that does NOT pass | openssl sha256 to the first openssl; instead it runs two different processes and redirects the output of the first to a pipe and the input of the second from that pipe. Runtime.exec() is NOT a command processor and cannot do this. You can:

  • run only the openssl rsa part, read the output in your Java code, and do the SHA256 of that output in Java

  • run a command interpreter and tell it to execute the compound command openssl rsa ... | openssl sha256 (all as one string). On Unix use an appropriate shell -- this may vary depending on your system but /bin/sh -c is common. On Windows use cmd.exe /c.

FYI, if you have or get the BouncyCastle libraries, they can read the same files openssl rsa can, and extract the modulus and format and hash it, all directly in Java without using openssl at all. But you didn't ask about that, so on Stack it's not an answer.

答案2

得分: 1

我的系统是Windows 10 x64,所以你可能需要调整路径以适应你的openssl.exe。

从解决方案路径开始,我首先运行了OpenSSL命令行:

    openssl rsa -noout -modulus -in keyunencrypted.pem | openssl sha256

这会得到以下结果作为参考:

    (stdin)= addc742adb857539b5b7240459e4341b8de7575b437459aacfab605dc46b5e9f

请注意,我使用的是 "**modulus**" 而不是你的命令字符串中的 "**modules**"。

在开始使用Java的经验中,我了解到通过Runtime.exec运行OpenSSL时会在一个shell中运行,但在通过Runtime.exec运行OpenSSL时并不是这样的。因此,有一种方法可以将完整的命令行拆分成两个单独的命令,通过输出 -&gt; 输入流进行组合。借助于Apache的common-io库,这可以很简单地实现。你可以从 https://mvnrepository.com/artifact/commons-io/commons-io 获取这个库,我在测试中使用了版本2.7。

下面的示例取自 https://stackoverflow.com/a/7226858/8166854,由用户@Bohemian编写,并给出了以下结果:

    [(stdin)= addc742adb857539b5b7240459e4341b8de7575b437459aacfab605dc46b5e9f]

这应该是预期的结果,通过一些字符串格式化,你可以得到你想要的结果。

这是源代码,请注意这里没有适当的异常处理。

    import org.apache.commons.io.IOUtils;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.nio.charset.StandardCharsets;
    import java.util.List;
    
    public class MainSo {
        public static void main(String[] args) throws IOException {
            System.out.println("https://stackoverflow.com/questions/63177584/java-error-in-executing-openssl-command-thorugh-runtime/63182609#63182609");
    
            String[] commands1 = new String[]{"E:\\intellij_projects\\openssl_1_1_1g-win64-mingw\\openssl.exe",
            "rsa", "-noout", "-modulus", "-in", "keyunencrypted.pem"};
            String[] commands2 = new String[]{"E:\\intellij_projects\\openssl_1_1_1g-win64-mingw\\openssl.exe", "sha256"};
    
            // https://stackoverflow.com/a/7226858/8166854
            // by @Bohemian
            // you need https://mvnrepository.com/artifact/commons-io/commons-io
            // commons-io-2.7.jar
            Process p1 = Runtime.getRuntime().exec(commands1);
            InputStream input = p1.getInputStream();
            Process p2 = Runtime.getRuntime().exec(commands2);
            OutputStream output = p2.getOutputStream();
            IOUtils.copy(input, output);
            output.close(); // signals command2 to finish
            List<String> result = IOUtils.readLines(p2.getInputStream(), StandardCharsets.UTF_8);
            System.out.println(result);
        }
    }
英文:

My system is Windows 10 x64 so maybe you have to adjust the paths to your openssl.exe.

Starting the solution path I firstly run the OpenSSL-command line:

openssl rsa -noout -modulus -in keyunencrypted.pem | openssl sha256

which gives this result as a reference:

(stdin)= addc742adb857539b5b7240459e4341b8de7575b437459aacfab605dc46b5e9f

Please note that I'm using "modulus" and not "modules" as in your commands-string.

Starting the Java experience I learned that opensll-command line runs in a shell but that's not doing when running
OpenSSL via Runtime.exec. Therefore, there is one way to split the complete command line into two separate commands combined via Output -> InputStream. There is a very simple solution for doing this with the help of Apache's common-io-library. You get the library from https://mvnrepository.com/artifact/commons-io/commons-io and
I used version 2.7 for my test.

The following example is taken from https://stackoverflow.com/a/7226858/8166854 and was written by User @Bohemian and gives the following result:

[(stdin)= addc742adb857539b5b7240459e4341b8de7575b437459aacfab605dc46b5e9f]

This should be the expected result and with a little string-formatting you get what you want.

Here is the source code, please keep in mind that there is no proper exception handling.

import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class MainSo {
    public static void main(String[] args) throws IOException {
        System.out.println(&quot;https://stackoverflow.com/questions/63177584/java-error-in-executing-openssl-command-thorugh-runtime/63182609#63182609&quot;);

        String[] commands1 = new String[]{&quot;E:\\intellij_projects\\openssl_1_1_1g-win64-mingw\\openssl.exe&quot;,
        &quot;rsa&quot;, &quot;-noout&quot;, &quot;-modulus&quot;, &quot;-in&quot;, &quot;keyunencrypted.pem&quot;};
        String[] commands2 = new String[]{&quot;E:\\intellij_projects\\openssl_1_1_1g-win64-mingw\\openssl.exe&quot;, &quot;sha256&quot;};

        // https://stackoverflow.com/a/7226858/8166854
        // by @Bohemian
        // you need https://mvnrepository.com/artifact/commons-io/commons-io
        // commons-io-2.7.jar
        Process p1 = Runtime.getRuntime().exec(commands1);
        InputStream input = p1.getInputStream();
        Process p2 = Runtime.getRuntime().exec(commands2);
        OutputStream output = p2.getOutputStream();
        IOUtils.copy(input, output);
        output.close(); // signals command2 to finish
        List&lt;String&gt; result = IOUtils.readLines(p2.getInputStream(), StandardCharsets.UTF_8);
        System.out.println(result);
    }
}

huangapple
  • 本文由 发表于 2020年7月31日 00:35:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/63177584.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定