Fixed Crypto errors and uncaught exceptions

The crypto salt file is no longer a thing. Now the salt is merely
appended to the `crypt_file` as the last sixteen bytes. The salt
is read from the end of the `crypt_file` on subsequent decryptions.

Added a setting for enabling 'debug' mode, using `pdb` for dynamic
debugging in pappy sessions. When needing to debug a function, or
set of functionality add the conditional `if config.debug`, then
set an entry point for `pdb` using `import pdb; pdb.set_trace()`
May remove this functionality if not desired in the main project.
master
Nich 8 years ago
parent 2df463fc79
commit 976287a67b
  1. 1
      pappyproxy/config.py
  2. 55
      pappyproxy/crypto.py
  3. 21
      pappyproxy/pappy.py

@ -164,6 +164,7 @@ class PappyConfig(object):
self.global_config_dict = {}
self.archive = 'project.archive'
self.debug = False
self.crypt_dir = 'crypt'
self.crypt_file = 'project.crypt'
self.crypt_session = False

@ -32,28 +32,33 @@ class Crypto(object):
"""
# Leave the crypto working directory
os.chdir('../')
if self.config.crypt_dir in os.getcwd():
os.chdir('../')
self.compressor.compress_project()
# Get the password and salt, then derive the key
self.crypto_ramp_up()
# Create project and crypto archive
archive_file = open(self.archive, 'rb')
archive_crypt = open(self.config.crypt_file, 'wb')
# Get the password and salt, then derive the key
self.crypto_ramp_up()
try:
# Encrypt the archive read as a bytestring
fern = Fernet(self.key)
crypt_token = fern.encrypt(archive_file.read())
archive_crypt.write(crypt_token)
except InvalidToken as e:
raise PappyException("Error encrypting project: ", e)
return False
# Encrypt the archive read as a bytestring
fern = Fernet(self.key)
crypt_token = fern.encrypt(archive_file.read())
archive_crypt.write(crypt_token)
archive_file.close()
archive_crypt.close()
# Store the salt for the next decryption
self.create_salt_file()
archive_file.close()
archive_crypt.close()
# Delete clear-text files
self.delete_clear_files()
return True
@ -79,6 +84,7 @@ class Crypto(object):
cf = self.config.crypt_file
sl = self.config.salt_len
crl = os.path.getsize(cf) - sl
archive_crypt = open(cf, 'rb').read(crl)
archive_file = open(self.config.archive, 'wb')
@ -89,18 +95,16 @@ class Crypto(object):
fern = Fernet(self.key)
archive = fern.decrypt(archive_crypt)
break
except InvalidToken:
print "Invalid password"
except InvalidToken as e:
print "Invalid decryption: ", e
retries -= 1
# Quit pappy if user doesn't retry
# or if all retries exhuasted
if not self.confirm_password_retry() or retries <= 0:
self.config.crypt_success = False
return False
else:
self.password = None
self.key = None
self.salt = None
pass
archive_file.write(archive)
@ -112,7 +116,7 @@ class Crypto(object):
return True
def confirm_password_retry(self):
answer = raw_input("Re-enter your password? (y/n)").strip()
answer = raw_input("Re-enter your password? (y/n): ").strip()
if answer[0] == "y" or answer[0] == "Y":
return True
else:
@ -121,7 +125,8 @@ class Crypto(object):
def crypto_ramp_up(self):
if not self.password:
self.get_password()
self.set_salt()
if not self.salt:
self.set_salt()
self.derive_key()
def get_password(self):
@ -137,7 +142,11 @@ class Crypto(object):
raise PappyException("Invalid password, try again")
def set_salt(self):
if os.path.isfile(self.config.crypt_file):
if self.config.crypt_dir in os.getcwd():
os.chdir('../')
self.set_salt_from_file()
os.chdir(self.config.crypt_dir)
elif os.path.isfile(self.config.crypt_file):
self.set_salt_from_file()
else:
self.salt = os.urandom(16)
@ -152,19 +161,17 @@ class Crypto(object):
# behavior.
salt_file = open(self.config.crypt_file, 'rb')
sl = self.config.salt_len
salt_file.seek(sl, 2)
# Negate the salt length to seek to the
# correct position in the buffer
salt_file.seek(-sl, 2)
self.salt = salt_file.read(sl)
salt_file.close()
except:
cf = self.config.crypt_file
raise PappyException("Unable to read %s" % cf)
def create_salt_file(self):
# WARNING: must open `crypt_file` in `wb` mode
# or `salt_file.seek()` will result in undefined
# behavior.
salt_file = open(self.config.crypt_file, 'wb')
# Seek to the end of the encrypted archive
salt_file.seek(0,2)
salt_file = open(self.config.crypt_file, 'a')
salt_file.write(self.salt)
salt_file.close()

@ -76,6 +76,9 @@ class PappySession(object):
self.config.load_from_file('./config.json')
self.config.global_load_from_file()
self.delete_data_on_quit = False
else:
self.complete_defer.callback(None)
return
# If the data file doesn't exist, create it with restricted permissions
if not os.path.isfile(self.config.datafile):
@ -153,10 +156,7 @@ class PappySession(object):
if self.crypto.encrypt_project():
return True
else:
errmsg = "There was an issue encrypting the project."
raise PappyException(errmsg)
reactor.stop()
defer.returnValue(None)
return False
def decrypt(self):
# Attempt to decrypt project archive
@ -164,10 +164,7 @@ class PappySession(object):
return True
# Quit pappy on failure
else:
errmsg = "There was an issue encrypting the project."
raise PappyException(errmsg)
reactor.stop()
defer.returnValue(None)
return False
@defer.inlineCallbacks
def cleanup(self, ignored=None):
@ -187,6 +184,7 @@ def parse_args():
parser = argparse.ArgumentParser(description='An intercepting proxy for testing web applications.')
parser.add_argument('-l', '--lite', help='Run the proxy in "lite" mode', action='store_true')
parser.add_argument('-d', '--debug', help='Run the proxy in "debug" mode', action='store_true')
try:
hlpmsg = ''.join(['Start pappy in "crypto" mode,',
'must supply a name for the encrypted',
@ -211,6 +209,10 @@ def parse_args():
else:
settings['crypt'] = None
if args.debug:
settings['debug'] = True
else:
settings['debug'] = False
return settings
def set_text_factory(conn):
@ -257,6 +259,9 @@ def main():
pappy_config.global_load_from_file()
session.delete_data_on_quit = False
if settings['debug']:
pappy_config.debug = True
yield session.start()
session.complete_defer.addCallback(lambda ignored: reactor.stop())

Loading…
Cancel
Save