2

I want to run the following command using Python on a Mac OS X computer:

openssl enc -aes-128-cbc -K $(echo -n 'blabla1' | xxd -p) -iv blabla2 -in /tmp/clair -nopad -out /tmp/crypte1 -d

Here is what I have tried:

clef = 'blabla1'
iv = 'blabla2'
arguments = ['openssl','enc', '-aes-128-cbc', '-K $(echo -n \'%s\' | xxd -p)' % clef ,'-iv' ,'%s' % iv,'-in', '/tmp/clair','-nopad','-out','/tmp/crypte1','-d']
execute = Popen(arguments, stdout=PIPE)
out, err = execute.communicate()

The command works fine from a terminal but I get an error from the Python script:

unknown option '-K $(echo -n 'blabla1' | xxd -p)'

I have tried several variants of python shell functions (os.system for example), but I have a problem in each case.

7
  • 1
    Mightn't that be a shell error message? Commented Mar 23, 2018 at 13:21
  • No because the command works fine in the terminal. I think python is changing something... Commented Mar 23, 2018 at 13:22
  • @Bob5421. Nope. Will explain momentarily. Commented Mar 23, 2018 at 13:23
  • Popen does not run a bash that could expand -K $(...). Commented Mar 23, 2018 at 13:32
  • You neglect to mention the fact that you got other error messages from os.system, and to show those messages. Commented Mar 23, 2018 at 14:02

2 Answers 2

4

There are a number of things that users often take for granted when using a shell. Some examples are:

  • Variable expansion (${var})
  • Input/output redirection (cmd > out < in)
  • Pipes (cmd1 | cmd2)
  • Subshell creation ($(cmd))

All of these are features that the shell sets up before passing the actual command to the system. Python's subprocess module does not do any of these things for you automatically, but it does give you the tools to emulate them.

You have correctly redirected your output to a pipe for your Python process to pick up. However, the subshell created by $(echo -n 'blabla1' | xxd -p) is not something that will get processed the way you want without a shell. There are two simple workarounds.

  1. The quick and dirty solution is to pass the entire command line in as a string to subprocess.Popen and set shell=True:

    execute = Popen("openssl enc -aes-128-cbc -K $(echo -n 'blabla1' | xxd -p) "
                    "-iv blabla2 -in /tmp/clair -nopad -out /tmp/crypte1 -d",
                    shell=True)
    

    This will pass the string to a shell instead of directly to the system, thereby giving you access all the behaviors that you expect from a shell. This approach has major security problems, and is not generally recommended. However, it is very easy, and it will get you started.

  2. Implement the convenience of $(... | ...) in your code directly by capturing the output of xxd to a string using subprocess.run. This is lengthier, but probably more robust and portable in the long run. It is certainly the option I would chose in a production environment:

    from subprocess import Popen, run
    
    value = run(['xxd', '-p'], input='blabla1', universal_newlines=True).stdout
    execute = Popen(['openssl', 'enc', '-aes-128-cbc', '-K', value,
                     '-iv', 'blabla2', '-in', '/tmp/clair', '-nopad',
                     '-out', '/tmp/crypte1', '-d'])
    

Since you are setting up your own pipes, you don't need to call echo any more (you never did really, xxd -p <<< 'blabla1' would have worked fine), and -K needs to be a separate argument.

Sign up to request clarification or add additional context in comments.

6 Comments

I have tried your solution 1. I get this error: "hex string is too long invalid hex key value". And i have no error if i launch directly from my terminal
Can you tell me the difference between running echo ... | xxd -p from the command line and running run(['xxd', '-p'], input='blabla1', universal_newlines=True).stdout in the Python shell?
@Bob5421. I'm assuming you were referring to the second option by the way.
@Bob5421. Could you also please edit a list of the alternatives you've tried and the errors they gave you into your question?
In fact i am wondering if the problem is not that some chars are not encoded on 1 byte
|
0

subprocess adds quotes " to the argument "-K $(echo -n 'blabla1' | xxd -p)". You can check by

print(subprocess.list2cmdline(execute.args))

Output:

openssl enc -aes-128-cbc "-K $(echo -n 'blabla1' | xxd -p)" -iv blabla2 -in /tmp/clair -nopad -out /tmp/crypte1 -d

3 Comments

That is a very minor issue and does not address the actual problem with the subshell OP is trying to create.
Well, of course its not full solution but it addresses the problem of Popen(arguments, stdout=PIPE) with subsell. Thank you for your comprehensive answser.
I've removed my downvote. You are right that this is not really a minor issue, and you did address the immediate question, even if the question is incomplete.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.