From 2df463fc79f8a0cd4f09b163620c9e6f9cc10693 Mon Sep 17 00:00:00 2001 From: Nich Date: Mon, 11 Apr 2016 18:36:47 -0400 Subject: [PATCH] Issues with decrypting project Pappy is no longer reading the salt correctly, and now fails out when raising an exception. Need to fix exception handling. --- pappyproxy/config.py | 14 ++++---------- pappyproxy/crypto.py | 38 ++++++++++++++++++++++++++------------ pappyproxy/pappy.py | 19 ++++++++++++------- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/pappyproxy/config.py b/pappyproxy/config.py index ed29e8a..04abe1d 100644 --- a/pappyproxy/config.py +++ b/pappyproxy/config.py @@ -130,14 +130,11 @@ class PappyConfig(object): :Default: False - .. data: salt_file + .. data: salt_len - Clear-text file containing the salt generated for key derivation. A new salt - will be generated each time the project is encrypted. After successfully - decrypting the project file (``project.crypt``), the salt file (``project.salt``) - will be deleted. + Length of the nonce-salt value appended to the end of `crypt_file` - :Default: ``project.salt`` + :Default: 16 """ def __init__(self): @@ -170,8 +167,7 @@ class PappyConfig(object): self.crypt_dir = 'crypt' self.crypt_file = 'project.crypt' self.crypt_session = False - self.crypt_success = False - self.salt_file = 'project.salt' + self.salt_len = 16 def get_default_config(self): default_config_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), @@ -185,8 +181,6 @@ class PappyConfig(object): pp = os.getcwd() + os.sep project_files = [pp+f for f in file_glob if os.path.isfile(pp+f)] - if self.salt_file in project_files: - project_files.remove(self.salt_file) if self.crypt_file in project_files: project_files.remove(self.crypt_file) diff --git a/pappyproxy/crypto.py b/pappyproxy/crypto.py index a8c16cd..79aed48 100644 --- a/pappyproxy/crypto.py +++ b/pappyproxy/crypto.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import crochet +import getpass import glob import os import pappyproxy @@ -55,6 +56,7 @@ class Crypto(object): # Delete clear-text files self.delete_clear_files() + return True def decrypt_project(self): """ @@ -74,7 +76,10 @@ class Crypto(object): # Otherwise, decrypt and decompress the project else: - archive_crypt = open(self.config.crypt_file, 'rb').read() + 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') retries = 3 @@ -103,11 +108,7 @@ class Crypto(object): self.compressor.decompress_project() - # Force generation of new salt and crypt archive - self.delete_crypt_files() - os.chdir(self.config.crypt_dir) - self.config.crypt_success = True return True def confirm_password_retry(self): @@ -130,27 +131,40 @@ class Crypto(object): """ encoded_passwd = "" try: - passwd = raw_input("Enter a password: ").strip() + passwd = getpass.getpass("Enter a password: ").strip() self.password = passwd.encode("utf-8") except: raise PappyException("Invalid password, try again") def set_salt(self): - if os.path.isfile(self.config.salt_file): + if os.path.isfile(self.config.crypt_file): self.set_salt_from_file() else: self.salt = os.urandom(16) def set_salt_from_file(self): try: - salt_file = open(self.config.salt_file, 'rb') - self.salt = salt_file.readline().strip() + # Seek to `salt_len` bytes before the EOF + # then read `salt_len` bytes to retrieve the salt + + # WARNING: must open `crypt_file` in `rb` mode + # or `salt_file.seek()` will result in undefined + # behavior. + salt_file = open(self.config.crypt_file, 'rb') + sl = self.config.salt_len + salt_file.seek(sl, 2) + self.salt = salt_file.read(sl) except: - raise PappyException("Unable to read project.salt") + cf = self.config.crypt_file + raise PappyException("Unable to read %s" % cf) def create_salt_file(self): - salt_file = open(self.config.salt_file, 'wb') - + # 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.write(self.salt) salt_file.close() diff --git a/pappyproxy/pappy.py b/pappyproxy/pappy.py index 0f248c9..83882d6 100755 --- a/pappyproxy/pappy.py +++ b/pappyproxy/pappy.py @@ -26,6 +26,7 @@ from . import context from . import crypto from . import http from .console import ProxyCmd +from .util import PappyException from twisted.enterprise import adbapi from twisted.internet import reactor, defer from twisted.internet.error import CannotListenError @@ -71,9 +72,7 @@ class PappySession(object): from . import proxy, plugin if self.config.crypt_session: - self.decrypt() - - if self.config.crypt_success: + if self.decrypt(): self.config.load_from_file('./config.json') self.config.global_load_from_file() self.delete_data_on_quit = False @@ -150,17 +149,23 @@ class PappySession(object): self.complete_defer = deferToThread(self.cons.cmdloop) self.complete_defer.addCallback(self.cleanup) - @defer.inlineCallbacks def encrypt(self): - yield self.crypto.encrypt_project() + if self.crypto.encrypt_project(): + return True + else: + errmsg = "There was an issue encrypting the project." + raise PappyException(errmsg) + reactor.stop() + defer.returnValue(None) - @defer.inlineCallbacks def decrypt(self): # Attempt to decrypt project archive if self.crypto.decrypt_project(): - yield True + return True # Quit pappy on failure else: + errmsg = "There was an issue encrypting the project." + raise PappyException(errmsg) reactor.stop() defer.returnValue(None)