1

For starters, I can't use any 3rd party modules and my code must work with Python 2.4 due to this being a large enterprise environment and this tool must work on vanilla 2.4 python installs with no third party modules.

I'm writing a wrapper for openssl that will be used to retrieve/store encrypted data, mainly usernames/passwords and other authentication type data.

I'm writing the create module which creates a new, empty encrypted pickle file.

Flow is as follows:

Create a picklelized object in memory which is basically a dictionary object. (pickle.dumps) Encrypt the resulting pickle string in memory (echo string | openssl.....) Write this new string out as a pickle object. (pickle.dump)

Here is my current attempt:

def create(self, wallet, cipher=None, passphrase=None, **kawrgs):

    self.wallet = wallet
    rawdata     = None
    encdata     = None
    outfile     = None

    try:
        outfile = open(self.wallet, 'w')
    except Exception, e:
        raise OpenSSLWalletError("Failed to open '%s' for writing" % self.wallet, None, None, None)

    if passphrase:
        self.passphrase = "-k %s" % passphrase
    else:
        self.passphrase = "-k ''"

    if cipher:
        self.cipher = cipher

    try:
        rawdata = pickle.dumps(self.data)
        cmd = "echo -en '%s' | %s %s -a -salt %s" % (rawdata, self.openssl, self.cipher, self.passphrase)
        os_cmd  = shlex.split(cmd)
        proc = subprocess.Popen(os_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        encdata, stderr = proc.communicate()
        pickle.dump(encdata, outfile)
    except Exception, e:
        raise OpenSSLWalletError("Failed to create encrypted wallet '%s'" % self.wallet, cmd.rstrip(), None, stderr.rstrip())

I believe my problem is related to pickle adding newlines in the middle of the object which then breaks the openssl command:

Here is what the string looks like after pickle.dumps (basically this is just an empty dictionary fed to pickle):

self.data='{}'
'(dp0
.'

If I print out the cmd before it's fed to Popen, it looks like this:

cmd='echo (dp0

. | /usr/bin/openssl aes-256-cbc -a -salt -k '''

I've tried escaping the string, shell=True, shell=False, etc....

Anyone know any tricks or ways I can work around this? I assume stripping out the newlines from the pickle object will then break the pickle format and it won't be loadable, correct?

Thanks for any help.

2
  • Forgot to add that "self.data = {}" is defined in the init method of this class. Commented Aug 13, 2015 at 16:04
  • This doesn't help your situation but seeing pickle is bleh. I would recommend not using pickle. Because you have to unpickle. Can't use any other means Commented Aug 13, 2015 at 16:07

1 Answer 1

1

Since rawdata can contain arbitrary binary data, I'd favor non-shell mode and pass the data directly into openssl's standard input through Popen.communicate(). The catch is you must also indicate to the Popen constructor that stdin should be piped.

rawdata = pickle.dumps(self.data)
cmd = [self.openssl, cipher, "-a", "-salt", "-k", passphrase or "''"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
encdata, stderr = proc.communicate(input=rawdata)

Also note that encdata will end in a newline.

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

8 Comments

Problem is openssl won't accept the data like this. That would be the equivalent of "openssl <args> < <data to be encrypted>
Also I always avoid Shell=True but in this case I tried it as a troubleshooting effort.
No, the data passed into the input parameter of proc.communicate() is passed to the standard input of the subprocess, which is what the echo was supposed to achieve.
Yea, in unix that is equivalent too "command < data" and openssl is hard-coded to not accept input like that. I tried it anyways... every possible permutation and it simply won't work. It will only allow you to cat/echo to the command. Granted, unless openssl was written this way for security reasons, the problem is the openssl command and it not being traditional unix-like... but then again, linux is riddled with non-conforming unix commands now days. This would probably work on Solaris or AIX.
Oh, sorry I see what you're saying now. I missed the < bracket in the first comment. It seems to be something odd about openssl; when I tried from the command line I had to send two EOFs to get it to run. Anyway, I played around with it for a while and go it to work from Python. I'd forgotten about also setting stdin=subprocess.PIPE in the Popen constructor.
|

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.