在查看了有关此问题和相关问题的答案之后,我使用一些建议的加密和隐藏秘密数据的方法整理了一些代码。此代码专门用于脚本必须在没有用户干预的情况下运行的情况(如果用户手动启动该脚本,则最好将其放入密码中,并仅将其保存在内存中,以解决此问题)。这种方法不是超级安全的。从根本上讲,脚本可以访问机密信息,因此具有完全系统访问权限的任何人都可以使用脚本及其关联文件,并且可以访问它们。id的作用是使偶然检查的数据变得模糊不清,并且如果对数据文件进行单独检查或一起检查而不使用脚本,则数据文件本身将保持安全。
我这样做的动机是通过一个项目对我的一些银行帐户进行轮询以监视交易-我需要它在后台运行,而不必每隔一两分钟重新输入一次密码。
只需将此代码粘贴到脚本的顶部,更改saltSeed,然后根据需要在代码中使用store(),retrieve()和require():
from getpass import getpass
from pbkdf2 import PBKDF2
from Crypto.Cipher import AES
import os
import base64
import pickle
saltSeed = 'mkhgts465wef4fwtdd'
PASSPHRASE_FILE = './secret.p'
SECRETSDB_FILE = './secrets'
PASSPHRASE_SIZE = 64
KEY_SIZE = 32
BLOCK_SIZE = 16
IV_SIZE = 16
SALT_SIZE = 8
def getSaltForKey(key):
return PBKDF2(key, saltSeed).read(SALT_SIZE)
def encrypt(plaintext, salt):
''' Pad plaintext, then encrypt it with a new, randomly initialised cipher. Will not preserve trailing whitespace in plaintext!'''
initVector = os.urandom(IV_SIZE)
key = PBKDF2(passphrase, salt).read(KEY_SIZE)
cipher = AES.new(key, AES.MODE_CBC, initVector)
return initVector + cipher.encrypt(plaintext + ' '*(BLOCK_SIZE - (len(plaintext) % BLOCK_SIZE)))
def decrypt(ciphertext, salt):
''' Reconstruct the cipher object and decrypt. Will not preserve trailing whitespace in the retrieved value!'''
key = PBKDF2(passphrase, salt).read(KEY_SIZE)
initVector = ciphertext[:IV_SIZE]
ciphertext = ciphertext[IV_SIZE:]
cipher = AES.new(key, AES.MODE_CBC, initVector)
return cipher.decrypt(ciphertext).rstrip(' ')
def store(key, value):
''' Sore key-value pair safely and save to disk.'''
global db
db[key] = encrypt(value, getSaltForKey(key))
with open(SECRETSDB_FILE, 'w') as f:
pickle.dump(db, f)
def retrieve(key):
''' Fetch key-value pair.'''
return decrypt(db[key], getSaltForKey(key))
def require(key):
''' Test if key is stored, if not, prompt the user for it while hiding their input from shoulder-surfers.'''
if not key in db: store(key, getpass('Please enter a value for "%s":' % key))
try:
with open(PASSPHRASE_FILE) as f:
passphrase = f.read()
if len(passphrase) == 0: raise IOError
except IOError:
with open(PASSPHRASE_FILE, 'w') as f:
passphrase = os.urandom(PASSPHRASE_SIZE)
f.write(base64.b64encode(passphrase))
try: os.remove(SECRETSDB_FILE)
except: pass
else:
passphrase = base64.b64decode(passphrase)
try:
with open(SECRETSDB_FILE) as f:
db = pickle.load(f)
if db == {}: raise IOError
except (IOError, EOFError):
db = {}
with open(SECRETSDB_FILE, 'w') as f:
pickle.dump(db, f)
require('id')
require('password1')
require('password2')
print
print 'Stored Data:'
for key in db:
print key, retrieve(key)
如果在秘密文件上设置os权限以仅允许脚本本身读取它们,并且脚本本身被编译并标记为仅可执行文件(不可读),则该方法的安全性将得到显着提高。其中一些可以自动化,但是我没有打扰。可能需要为该脚本设置一个用户,然后以该用户身份运行该脚本(并将脚本文件的所有权设置给该用户)。
我喜欢任何人都能想到的任何建议,批评或其他弱点。我对编写加密代码非常陌生,因此我所做的工作几乎可以肯定会得到改善。