import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
// Set the key and iv values
String key = "1234567812345678";
String iv = "1234567812345678";
// Set the string to encrypt
String string = "passwordToBeEncrypted";
// Create the ProcessBuilder object and specify the command and its arguments
ProcessBuilder pb = new ProcessBuilder("echo", string, "|", "openssl enc -aes-256-cbc -k", key, "-iv", iv, "-base64");
// Start the process and get the Process object
Process p = pb.start();
// Wait for the process to finish and get the exit code
int exitCode = p.waitFor();
System.out.println("Exit code: " exitCode);
// Read the output from the process
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String encryptedString = reader.readLine();
// Print the encrypted string
System.out.println("Encrypted string: " encryptedString);
}
}
I am expecting the output to be a encrypted string whereas the actual output is command itself ie its printing the command "Encrypted string: passwordToBeEncrypted | openssl enc -aes-256-cbc -k 1234567812345678 -iv 1234567812345678 -base64 " Please point the issue with the above code.
I am trying to execute the below shell commands from java code -
key="1234567812345678" iv="1234567812345678"
string="passwordToBeEncrypted "
encrypted_string=$(echo "$string" | openssl enc -aes-256-cbc -k "$key" -iv "$iv" -base64)
echo "$encrypted_string"
CodePudding user response:
As our deceased chief executive commented, Java ProcessBuilder
(and also Runtime.exec
) is not a shell -- and it does not run Unix 'commands' but rather programs. Many of the commands you give to a Unix shell actually run a program, but they can do other things as well such as piping or otherwise redirecting I/O, and substituting variables as in the commands you posted, and ProcessBuilder
does not do these other things with the exception of piping in Java 9 up. See the compilation in my answer at Shell command in Java with Runtime.getRuntime().exec(); .
However, you don't actually need a pipeline; ProcessBuilder
by default redirects the stdin and stdout (and also stderr) of the program it runs to pipes respectively from and to the Java process, which your code can use. In particular while the Unix shell commandline
echo string | openssl enc ...
runs the echo
program to output 'string' (plus a newline) which is redirected to a pipe that is then redirected as the input of the openssl
program, in some shells you can get exactly the same result from
openssl <<<string enc ...
which runs one program, openssl
, with its input redirected from a tempfile or pipe created by the shell itself (not a separate program) and ProcessBuilder
can effectively do this latter:
String key = "1234567812345678";
String iv = "1234567812345678";
String string = "passwordToBeEncrypted";
ProcessBuilder pb = new ProcessBuilder("openssl","enc","-aes-256-cbc","-k",key,"-iv",iv,"-base64");
// note every token parsed from the shell command as a separate argument (which is every one
// separated by unquoted whitespace) must be a separate argument to ProcessBuilder
Process p = pb.start();
// **CHANGE HERE**
p.getOutputStream.write( (string "\n").getBytes(/*charset if needed*/) );
p.getOutputStream.close();
// instead of using the OutputStream directly you can wrap (a) Writer(s) on it and use that(them),
// similar to the way you wrap Readers on the InputStream below, but I didn't bother
// if the data contains any non-ASCII character(s) then the 'charset' used for encoding matters;
// you need to specify it in `String.getBytes()`, or when creating Writer(s) if you do that,
// as a Java value equivalent to the 'locale' used by the echo program in your shell,
// which will generally be the setting of the env var LC_ALL or LANG --
// but your posted data is all ASCII so all charsets Java can default to are okay
int exitCode = p.waitFor();
System.out.println("Exit code: " exitCode);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String encryptedString = reader.readLine();
System.out.println("Encrypted string: " encryptedString);
PS: all of the attempts/versions you posted encrypt -- not decrypt -- a string, in a particular way idiosyncratic to openssl
that is not fully standard and not even very good, see (my) https://crypto.stackexchange.com/questions/3298/is-there-a-standard-for-openssl-interoperable-aes-encryption/#35614 . And you don't actually need to run openssl
; Java's own cryptographic functions can do exactly the same thing, although if you don't have and use the BouncyCastle third-party libraries you need some code to put together several primitives to produce the same results as openssl's EVP_BytesToKey
. There are numerous existing Qs on this, going back many years; I'll try to dig up some later. But of course you didn't ask about doing the cryptography, much less doing good cryptography, only about running the particular program specified.
CodePudding user response:
You need to be running the shell first (pipes are a shell thing) and then pass the correct program and arguments to it. Tested and working with Java 8:
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
// Set the key and iv values
String key = "1234567812345678";
String iv = "1234567812345678";
// Set the string to encrypt
String string = "passwordToBeEncrypted";
// Create the ProcessBuilder object and specify the command and its arguments
String command = String.format("echo %s | openssl enc -aes-256-cbc -k %s -iv %s -base64", string, key, iv);
ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
pb.inheritIO();
// Start the process and get the Process object
Process p = pb.start();
// Wait for the process to finish and get the exit code
int exitCode = p.waitFor();
System.out.println("Exit code: " exitCode);
}
}