^&'\"\\ " fun fx( srcPath: Path, password: String = "", ) { val processBuilder = ProcessBuilder( li" /> ^&'\"\\ " fun fx( srcPath: Path, password: String = "", ) { val processBuilder = ProcessBuilder( li" /> ^&'\"\\ " fun fx( srcPath: Path, password: String = "", ) { val processBuilder = ProcessBuilder( li"/>

How to pass password with special character in 7z cmd ProcessBuilder

158 views Asked by At

I have an encrypted archive with password " /?*:<|>^&'\"\\ "

fun fx(
        srcPath: Path,
        password: String = "",
    ) {
        val processBuilder = ProcessBuilder(
            libPath,
            "t",
            srcPath.absolutePathString(),
            "-bsp1",
            "-p$password",
        )

        processBuilder.redirectErrorStream(true)

        println("pass:$password")
        println("passArg:${processBuilder.command().last()}")

        val process = processBuilder.start()

        println(
            process.stdOutput()
        )
    }

I get:

pass:" /?*:<|>^&'\"\\ "
passArg:-p" /?*:<|>^&'\"\\ "

7-Zip 22.01 ZS v1.5.5 R2 (x64) : Copyright (c) 1999-2022 Igor Pavlov, 2016-2023 Tino Reichardt : 2023-04-05

Scanning the drive for archives:
1 file, 196620033 bytes (188 MiB)

Testing archive: D:\Games\X\special.7z
ERROR: D:\Games\X\special.7z
Cannot open encrypted archive. Wrong password?

    
Can't open as archive: 1
Files: 0
Size:       0
Compressed: 0

if I provide a wrong pass without special chars

10:04:56.831389500  INFO [                main] :        Configuration : Configuration set using the DSL with append=false
pass:a
passArg:-pa

7-Zip 22.01 ZS v1.5.5 R2 (x64) : Copyright (c) 1999-2022 Igor Pavlov, 2016-2023 Tino Reichardt : 2023-04-05

Scanning the drive for archives:
1 file, 196620033 bytes (188 MiB)

Testing archive: D:\Games\X\special.7z
ERROR: D:\Games\X\special.7z
Cannot open encrypted archive. Wrong password?

    
Can't open as archive: 1
Files: 0
Size:       0
Compressed: 0

how do I handle this?

trying on a different archive with no special char password, I get:

pass:a
passArg:-pa

7-Zip 22.01 ZS v1.5.5 R2 (x64) : Copyright (c) 1999-2022 Igor Pavlov, 2016-2023 Tino Reichardt : 2023-04-05

Scanning the drive for archives:
1 file, 174698897 bytes (167 MiB)

Testing archive: D:\Games\X\nospecialenc.7z
--
Path = D:\Games\X\nospecialenc.7z
Type = 7z
Physical Size = 174698897
Headers Size = 1377
Method = LZMA2:23 BCJ 7zAES
Solid = +
Blocks = 2

Everything is Ok

Folders: 36
Files: 47
Size:       605457431
Compressed: 174698897

I can extract the archive with the exact pass " /?*:<|>^&'\"\\ " (with the double quotation) in GUI. How do I handle this here?

Update: I've updated to fulfill the concerns mentioned in the comments.

1

There are 1 answers

2
VonC On BEST ANSWER

From this thread, that does not seem possible, in JVM-based language or even in CLI.

When I tried to create an archive with that password:

password

It triggered the warning:

Warning

" character is not recommended to be used in passwords (for PeaZup and scripts). If you need to create or extract an archive with this password, you can dismiss the message, and you will be asked to enter the password interactively in console.

I had to select "Force typing passwords interactively" to be able to set the password (as mentioned before, "interactively in console"):

set password

That means the password will have to be entered interactively for decryption. No -pxxx possible.


Can you show some sample jvm code on how to do it interactively?

7z.exe should stops its stdout output, waiting for stdin input for the password.
You would need to use ProcessBuilder to start the process and then handling the input and output streams to provide the password.

import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

public class Run7zWithPassword {
    
    public static void main(String[] args) {
        // Command to list contents of a password-protected archive
        String[] command = {"7z.exe", "l", "path\\to\\your\\archive.7z"};
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        
        try {
            Process process = processBuilder.start();
            
            // Writing the password to the process's output stream (which is input for the process)
            try (OutputStream outputStream = process.getOutputStream()) {
                String password = "yourPasswordHere\n"; // Password with a newline character
                outputStream.write(password.getBytes(StandardCharsets.UTF_8));
                outputStream.flush();
            }
            
            // Handling the output (and potentially the input) of the process
            handleProcessOutput(process);
            
            int exitCode = process.waitFor();
            System.out.println("Process exited with code " + exitCode);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    private static void handleProcessOutput(Process process) throws IOException {
        try (InputStream inputStream = process.getInputStream();
             InputStream errorStream = process.getErrorStream()) {
            
            // Optionally, handle inputStream and errorStream to read output and errors
            
            // Example of reading the process's output stream (stdout)
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                System.out.write(buffer, 0, length);
            }
            
            // Example of reading the process's error stream (stderr)
            while ((length = errorStream.read(buffer)) != -1) {
                System.err.write(buffer, 0, length);
            }
        }
    }
}

The handleProcessOutput method in the example reads both the standard output (stdout) and standard error (stderr) streams of the process to make sure all output is captured and displayed.
The password is directly in that code, just from testing.