Hmm - I'm new, but is this request really off topic? It seems ok to me...
If you use Python and GIT, then we coded up a solution for storing passwords (and other config info) as regular variables, using RC4. It made it easy for us to maintain passwords in plaintext on dev machines, have the passwords encrypted automatically, and an encrypted version distributed automatically with every git push. You need to manually install a private key on each production machine, but thereafter git pulls on the production machine will pull in an updated encrypted file and automatically decrypt it at runtime for use within your code.
One nice feature of the code is that a decrypted (plaintext) copy of your passwords never, ever hits the hard drive on a production machine. And yet you can directly reference your passwords within your python code, and most intellisense systems (such as pyCharm's) can view the password variables during coding on the production machine. It is also very easy to change passwords - just update the plaintext file and git push.
I haven't contributed anything to SO yet, so I might as well start now. I put the code, along with a complete ReadMe, on a GitHub repo:
https://github.com/KenYounge/security
After grabbing the security.py file, implementation is as simple as:
import security
for line in security.secure(): exec line in globals()
There is a complete README.md file and helloworld.py example in the github repo. Here is the implementation code in case someone wants to comment:
"""Secure python variables: encrypt, decrypt, import into global namespace."""
__module__ = 'security.py'
__author__ = "Kenneth A Younge"
__copyright__ = "Copyright (c) 2014, Kenneth A. Younge"
__license__ = "GNU General Public License"
__email__ = "[email protected]"
import os
def crypt(data, key):
x = 0
box = range(256)
for i in range(256):
x = (x + box[i] + ord(key[i % len(key)])) % 256
box[i], box[x] = box[x], box[i]
x = 0
y = 0
out = []
for char in data:
x = (x + 1) % 256
y = (y + box[x]) % 256
box[x], box[y] = box[y], box[x]
out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256]))
return ''.join(out)
def secure(file_names=('passwords.py',),
key_name='security.key',
key_path='~/',
pvt_path='_private/',
verbose=False):
"""Transform files (encrypt and/or decrypt _private files).
Keyword arguments:
filenames -- sequence of file names to encrypt/decrypt
key_name -- file name of your personal rc4 encryption key
key_path -- location of encryption key on production machines
pvt_path -- location of private files and encryption key during dev
verbose -- print info
Defaults:
filenames -- passwords.py currently a tuple with one file
key_name -- security.key
key_path -- ~/
pvt_path -- _private/
verbose -- False
"""
# Load key (try production location first)
if os.path.exists(os.path.join(key_path, key_name)):
key = open(os.path.join(key_path, key_name), 'r').read()
elif os.path.exists(os.path.join(
os.path.dirname(__file__), pvt_path + key_name)):
key = open(os.path.join(
os.path.dirname(__file__), pvt_path + key_name), 'r').read()
else:
key = open(os.path.join(
os.path.dirname(__file__), key_name), 'r').read()
# secure each file
code_lines = []
for filename in file_names:
filename_raw = os.path.join(
os.path.dirname(__file__), pvt_path + filename)
filename_rc4 = os.path.join(
os.path.dirname(__file__),
os.path.basename(filename).replace('.py', '.rc4'))
# Encrypt
try:
if os.path.exists(filename_raw):
with open(filename_raw, 'r') as f:
text = f.read()
with open(filename_rc4, 'w') as f:
f.write(crypt(str(text).strip(), key).encode('hex'))
if verbose:
print 'Encrypted ' + filename_raw
else:
if verbose:
print('File (' + filename_raw + ') not found')
except Exception as e:
print(str(e))
# Decrypt
try:
if os.path.exists(filename_rc4):
with open(filename_rc4, 'r') as f:
text = crypt(str(f.read()).strip().decode('hex'), key)
lines = [str(line).strip() for line in text.splitlines()]
if lines: code_lines.extend(lines)
if verbose:
print 'Encrypted ' + filename_rc4
else:
print('File ' + filename_rc4 + ' not found')
except Exception as e:
print(str(e))
return code_lines