1
\$\begingroup\$

I'm writing a tool, to manage our application, specifically to store passwords in encrypted view. I made a class which is based on two posts:

https://stackoverflow.com/questions/20852664/python-pycrypto-encrypt-decrypt-text-files-with-aes

and:

https://stackoverflow.com/questions/4102761/python-config-parser-cache-to-reduce-i-o-on-an-embedded-system

#!/usr/bin/env python

import os

import StringIO
import hashlib

from Crypto import Random
from Crypto.Cipher import AES

from lib.shared import ConfigParser


class RDSCryptor(object):

    def __init__(self, rdsmanager_local_path):

        password = 'password'
        self.key = hashlib.sha256(password).digest()

        self.passfile_enc = os.path.join(rdsmanager_local_path, 'conf', 'credentials.txt.enc')
        self.passfile_clear = os.path.join(rdsmanager_local_path, 'conf', 'credentials.txt')

    def pad(self, s):

        return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

    def encrypt(self, message):

        message = self.pad(message)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)

        return iv + cipher.encrypt(message)

    def decrypt(self, ciphertext):

        iv = ciphertext[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        plaintext = cipher.decrypt(ciphertext[AES.block_size:])

        return plaintext.rstrip(b"\0")

    def encrypt_file(self):

        with open(self.passfile_enc, 'rb') as fo:
            plaintext = fo.read()
        enc = self.encrypt(plaintext)

        with open(self.passfile_enc + '.enc', 'wb') as fo:
            fo.write(enc)

    def decrypt_file(self):

        with open(self.passfile_enc, 'rb') as fo:
            ciphertext = fo.read()

        dec = self.decrypt(ciphertext)

        return dec

    def get_credentials(self, section, option):

        buf = StringIO.StringIO(self.decrypt_file())

        config = ConfigParser.ConfigParser()
        config.readfp(buf)

        return config.get(section, option)

Cleartext file (it's not stored in project's repository) looks like:

[cloudlibrary]
clc_user = username
clc_password = password

[kantar_smtp]
smtpconnect_user = username
smtpconnect_password = password

Thet - this class used in main tool's script with:

...
# Cloudlibrary access data
crypto = RDSCryptor(rdsmanager_local_path)

clc_user = crypto.get_credentials('cloudlibrary', 'clc_user')
clc_password = crypto.get_credentials('cloudlibrary', 'clc_password')

# Sendmail credentials
smtpconnect_user = crypto.get_credentials('kantar_smtp', 'smtpconnect_user')
smtpconnect_password = crypto.get_credentials('kantar_smtp', 'smtpconnect_password')
...

All I want is to hide plaintext from the source code - it's not intended to be super-secure against hackers.

What is wrong or can it be done better here?

\$\endgroup\$
  • 1
    \$\begingroup\$ Have you looked at the keyring module? That provides access to the system keychain for storing passwords, which is probably better than rolling your own crypto. \$\endgroup\$ – alexwlchan Sep 24 '15 at 13:32
  • \$\begingroup\$ @alexwlchan Huh! I googled, of course - but doesn't found this mod :-( Thanks... Seems I reinvented the bicycle :-) \$\endgroup\$ – setevoy Sep 24 '15 at 13:34
1
\$\begingroup\$

You don't need to declare password to just use on the next line and never again. Use the literal directly:

self.key = hashlib.sha256('password').digest()

You have some confusing names, like s and iv. Renaming these to be more explicit, like string for s would make it more readable. As would adding docstrings or (less preferably) comments to explain the context of what each function is exactly. At the very least your overall class should have a docstring for a user to know about the general practice of the class.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.