5

I'm trying to unzip a file with 7z.exe and the password contains special characters on it

EX. &)kra932(lk0¤23

By executing the following command:

subprocess.call(['7z.exe', 'x', '-y', '-ps^&)kratsaslkd932(lkasdf930¤23', 'file.zip'])

7z.exe launches fine but it says the password is wrong.

This is a file I created and it is driving me nuts.

If I run the command on the windows command line it runs fine

7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip

How can I make python escape the & character?


@Wim the issue occurs & on the password, because when i execute

7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip 

it says invalid command ')kratsaslkd932(lkasdf930¤23' im using python 2.76, cant upgrade to 3.x due to company tools that only run on 2.76

tshepang
  • 12,111
  • 21
  • 91
  • 136
Barecool
  • 78
  • 1
  • 9
  • Sounds like Python 2.7! If so: `subprocess.call(['7z.exe', 'x', '-y', u'-ps^&)kratsaslkd932(lkasdf930¤23', 'file.zip'])` – This company is turning evil. Feb 06 '14 at 18:48
  • 1
    At which character does your password start? the example password is different from that which you're actually using. – wim Feb 06 '14 at 18:49
  • What version of Python? What sort of special characters, e.g. non-alphanumeric, unicode, bash escape characters? I see all three in your example. – dimo414 Feb 06 '14 at 18:54
  • btw I think your problem is the ¤ character, not the &. Kroltans suggestion above should probably work! – wim Feb 06 '14 at 18:57
  • if running on python3 is an option, your code as-is might just work too. – wim Feb 06 '14 at 18:57
  • @wim the issue occurs & on the password, because when i execute 7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip it says invalid command ')kratsaslkd932(lkasdf930¤23' im using python 2.76, cant upgrade to 3.x due to company tools that only run on 2.76 – Barecool Feb 07 '14 at 20:15

3 Answers3

1

There is a big security risk in passing the password on the command line. With administrative rights, it is possible to retrieve that information (startup info object) and extract the password. A better solution is to open 7zip as a process, and feed the password into its standard input.

Here is an example of a command line that compresses "source.txt" into "dest.7z":

CMD = ['c:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-p', 'c:\\source.txt', 'd:\\dest.7z']
PASSWORD = "Nj@8G86Tuj#a"

First you need to convert the password into an input string. Please note that 7-zip expects the password to by typed into the terminal. You can use special characters as long as they can be represented in your terminal. The encoding of the terminal matters! For example, on Hungarian Windows, you might want to use "cp1250" encoding. In all cases, the standard input is a binary file, and it expects a binary string ("bytes" in Python 3). If you want to be on the safe side, you can restrict passwords to plain ascii and create your input like this:

input = (PASSWORD + "\r\n").encode("ascii")

If you know the encoding of your terminal, then you can convert the password to that encoding. You will also be able to detect if the password cannot be used with the system's encoding. (And by the way, it also means that it cannot be used interactively either.)

(Last time I checked, the terminal encoding was different for different regional settings on Windows. Maybe there is a trick to change that to UTF-8, but I'm not sure how.)

This is how you execute a command:

import subprocess
import typing

def execute(cmd : typing.List[str], input: typing.Optional[bytes] = None, verbose=False, debug=False, normal_priority=False):
    if verbose:
        print(cmd)
    creationflags = subprocess.CREATE_NO_WINDOW
    if normal_priority:
        creationflags |= subprocess.NORMAL_PRIORITY_CLASS
    else:
        creationflags |= subprocess.BELOW_NORMAL_PRIORITY_CLASS

    if debug:
        process = subprocess.Popen(cmd, shell=False, stdout=sys.stdout, stderr=sys.stderr, stdin=subprocess.PIPE,
                                   creationflags=creationflags)
    else:
        process = subprocess.Popen(cmd, shell=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
                                   stdin=subprocess.PIPE, creationflags=creationflags)
    if input:
        process.stdin.write(input)
        process.stdin.flush()
    returncode = process.wait()
    if returncode:
        raise OSError(returncode)


CMD = ['c:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-p', 'c:\\source.txt', 'd:\\dest.7z']
PASSWORD = "Nj@8G86Tuj#a"
input = (PASSWORD + "\r\n").encode("ascii")
execute(CMD, input)

This also shows how to lower process priority (which is usually a good idea when compressing large amounts of data), and it also shows how to forward standard output and standard error to the console.

The absolute correct solution would be to load 7-zip DLL and use its API. (I did not check but that can probably use 8 bit binary strings for passwords.)

Note: this example is for Python 3 but the same can be done with Python 2.

nagylzs
  • 3,954
  • 6
  • 39
  • 70
0

I'd suggest using a raw string and the shlex module (esp. on Windows) and NOT supporting any encoding other than ASCII.

import shlex
import subprocess

cmd = r'7z.exe x -y -p^&moreASCIIpasswordchars file.zip'
subprocess.call(shlex.split(cmd))

Back to the non-ASCII character issue...

I'm pretty sure in Python versions < 3 you simply can't use non-ASCII characters. I'm no C expert, but notice the difference between 2.7 and 3.3. The former uses a "standard" char while the later uses a wide char.

marklap
  • 471
  • 4
  • 15
-1

Try to put double quotes between your password, otherwise the cmd parser would any parse special character as is instead of taking it as part of the password.

For example, 7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip won't work.

But 7z.exe x -y -p"s^&)kratsaslkd932(lkasdf930¤23" file.zip would definitely work.

Castiel Wong
  • 119
  • 2
  • 3
  • This is completely wrong where a shell is not involved. If there was a `shell=True` this would be both necessary and useful; but there isn't one. See also https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess – tripleee Sep 07 '19 at 11:09