Debugging Crypto config and temp directory creation

Attempting to get stub file creation and copying working. Fixed
syntax errors, and now attempting to get password reading working
in the test environment.
master
onizenso 8 years ago
parent ad37727c6b
commit b56bb83558
  1. 4
      pappyproxy/Makefile
  2. 17
      pappyproxy/config.py
  3. 81
      pappyproxy/crypto.py
  4. 11
      pappyproxy/pappy.py
  5. 51
      pappyproxy/tests/test_crypto.py

@ -16,3 +16,7 @@ test-proxy:
test-comm: test-comm:
py.test -v -rw --twisted tests/test_comm.py py.test -v -rw --twisted tests/test_comm.py
test-crypto:
py.test -v -rw --twisted tests/test_crypto.py

@ -1,3 +1,4 @@
import glob
import json import json
import os import os
import shutil import shutil
@ -175,7 +176,7 @@ class PappyConfig(object):
self.crypt_dir = os.path.join(os.getcwd(), 'crypt') self.crypt_dir = os.path.join(os.getcwd(), 'crypt')
self.crypt_file = 'project.crypt' self.crypt_file = 'project.crypt'
self.crypt_mode = None self.crypt_mode = None
self.salt = os.urandom(16) self.salt = os.urandom(16)
self.salt_file = 'project.salt' self.salt_file = 'project.salt'
def get_default_config(self): def get_default_config(self):
@ -186,12 +187,14 @@ class PappyConfig(object):
return settings return settings
def get_project_files(self): def get_project_files(self):
file_glob = glob.glob('*') file_glob = glob.glob('*')
pp = os.path.join(os.getcwd()) pp = os.path.join(os.getcwd())
project_files = [pp+f for f in file_glob if os.path.isfile(pp+f)] project_files = [pp+f for f in file_glob if os.path.isfile(pp+f)]
project_files.remove(self.salt_file) if self.salt_file in project_files:
project_files.remove(self.crypt_file) project_files.remove(self.salt_file)
return project_files if self.crypt_file in project_files:
project_files.remove(self.crypt_file)
return project_files
@staticmethod @staticmethod

@ -10,7 +10,7 @@ import twisted
from . import compress from . import compress
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
from cryptography import Fernet from cryptography.fernet import Fernet
from twisted.internet import reactor, defer from twisted.internet import reactor, defer
class Crypto(object): class Crypto(object):
@ -18,16 +18,20 @@ class Crypto(object):
self.config = sessconfig self.config = sessconfig
self.archive = self.config.archive self.archive = self.config.archive
self.compressor = compress.Compress(sessconfig) self.compressor = compress.Compress(sessconfig)
self.key = None
self.password = None
self.salt = None
def encrypt_project(passwd): def encrypt_project(self):
""" """
Compress and encrypt the project files, deleting clear-text files afterwards Compress and encrypt the project files, deleting clear-text files afterwards
""" """
# Derive the key
key = crypto_ramp_up(passwd) # Get the password and salt, then derive the key
self.crypto_ramp_up()
# Instantiate the crypto module # Instantiate the crypto module
fern = Fernet(key) fern = Fernet(self.key)
# Create project archive and crypto archive # Create project archive and crypto archive
self.compressor.compress_project() self.compressor.compress_project()
@ -39,24 +43,26 @@ class Crypto(object):
archive_crypt.write(crypt_token) archive_crypt.write(crypt_token)
# Delete clear-text files # Delete clear-text files
delete_clear_files() # delete_clear_files()
# Leave crypto working directory # Leave crypto working directory
os.chdir('../') os.chdir('../')
@defer.inlineCallbacks def decrypt_project(self):
def decrypt_project(passwd):
""" """
Decrypt and decompress the project files Decrypt and decompress the project files
""" """
# Get the password and salt, then derive the key
self.crypto_ramp_up()
# Create crypto working directory # Create crypto working directory
crypto_path = os.path.join(os.getcwd(), pappy_config.crypt_dir) crypto_path = os.path.join(os.getcwd(), self.config.crypt_dir)
os.mkdir(crypto_path) os.mkdir(crypto_path)
if os.path.isfile(self.config.crypt_file): if os.path.isfile(self.config.crypt_file):
# Derive the key # Derive the key
key = crypto_ramp_up(passwd) key = self.crypto_ramp_up()
fern = Fernet(key) fern = Fernet(key)
# Decrypt the project archive # Decrypt the project archive
@ -71,18 +77,14 @@ class Crypto(object):
for pf in project_files: for pf in project_files:
shutil.copy2(pf, crypto_path) shutil.copy2(pf, crypto_path)
os.chdir(crypto_path) os.chdir(crypto_path)
def crypto_ramp_up(self):
def crypto_ramp_up(passwd): if not self.password:
salt = "" self.get_password()
if os.path.isfile(self.config.salt_file): self.set_salt()
salt = get_salt() self.derive_key()
else:
salt = create_salt_file() def delete_clear_files(self):
key = derive_key(passwd, salt)
return key
def delete_clear_files():
""" """
Deletes all clear-text files left in the project directory. Deletes all clear-text files left in the project directory.
""" """
@ -90,7 +92,7 @@ class Crypto(object):
for pf in project_files: for pf in project_files:
os.remove(pf) os.remove(pf)
def delete_crypt_files(): def delete_crypt_files(self):
""" """
Deletes all encrypted-text files in the project directory. Deletes all encrypted-text files in the project directory.
Forces generation of new salt after opening and closing the project. Forces generation of new salt after opening and closing the project.
@ -99,22 +101,29 @@ class Crypto(object):
os.remove(self.config.salt_file) os.remove(self.config.salt_file)
os.remove(self.config.crypt_file) os.remove(self.config.crypt_file)
def create_salt_file(): def create_salt_file(self):
self.config.salt = urandom(16)
salt_file = open(self.config.salt_file, 'wb') salt_file = open(self.config.salt_file, 'wb')
if not self.config.salt:
self.set_salt()
salt_file.write(self.config.salt) salt_file.write(self.config.salt)
salt_file.close() salt_file.close()
return salt
def get_salt(): def set_salt_from_file(self):
try: try:
salt_file = open(self.config.salt_file, 'rb') salt_file = open(self.config.salt_file, 'rb')
salt = salt_file.readline() self.config.salt = salt_file.readline().strip()
except: except:
raise PappyException("Unable to read pappy.salt") raise PappyException("Unable to read project.salt")
return salt
def set_salt(self):
if os.path.isfile(self.config.salt_file):
self.set_salt_from_file()
else:
self.config.salt = os.urandom(16)
def get_password(): def get_password(self):
""" """
Retrieve password from the user. Raise an exception if the Retrieve password from the user. Raise an exception if the
password is not capable of utf-8 encoding. password is not capable of utf-8 encoding.
@ -122,12 +131,11 @@ class Crypto(object):
encoded_passwd = "" encoded_passwd = ""
try: try:
passwd = raw_input("Enter a password: ") passwd = raw_input("Enter a password: ")
encode_passwd = passwd.encode("utf-8") self.password = passwd.encode("utf-8")
except: except:
raise PappyException("Invalid password, try again") raise PappyException("Invalid password, try again")
return encoded_passwd
def derive_key(passwd, salt): def derive_key(self):
""" """
Derive a key sufficient for use as a cryptographic key Derive a key sufficient for use as a cryptographic key
used to encrypt the project (currently: cryptography.Fernet). used to encrypt the project (currently: cryptography.Fernet).
@ -156,9 +164,8 @@ class Crypto(object):
- scrypt.error if scrypt failed - scrypt.error if scrypt failed
""" """
derived_key = ""
try: try:
dkey = scrypt.hash(passwd, salt, bufflen=32) if not self.key:
self.key = scrypt.hash(self.password, self.salt, bufflen=32)
except e: except e:
raise PappyException("Error deriving the key: ", e) raise PappyException("Error deriving the key: ", e)
return derived_key

@ -64,7 +64,7 @@ class PappySession(object):
self.dbpool = None self.dbpool = None
self.delete_data_on_quit = False self.delete_data_on_quit = False
self.ports = None self.ports = None
self.crypto = Crypto(sessconfig) self.crypto = crypto.Crypto(sessconfig)
self.password = None self.password = None
@defer.inlineCallbacks @defer.inlineCallbacks
@ -145,16 +145,11 @@ class PappySession(object):
@defer.inlineCallbacks @defer.inlineCallbacks
def encrypt(self): def encrypt(self):
if self.password: self.crypto.encrypt_project(self.password)
self.crypto.encrypt_project(self.password)
else:
self.password = self.crypto.get_password()
self.crypto.encrypt_project(self.password)
@defer.inlineCallbacks @defer.inlineCallbacks
def decrypt(self): def decrypt(self):
self.password = self.crypto.get_password() self.crypto.decrypt_project()
self.crypto.decrypt_project(self.password)
@defer.inlineCallbacks @defer.inlineCallbacks
def cleanup(self, ignored=None): def cleanup(self, ignored=None):

@ -0,0 +1,51 @@
import os
import pytest
import random
import string
from pappyproxy.session import Session
from pappyproxy.crypto import Crypto
from pappyproxy.config import PappyConfig
@pytest.fixture
def conf():
c = PappyConfig()
return c
@pytest.fixture
def crypt():
c = Crypto(conf())
return c
@pytest.fixture
def tmpname():
cns = string.ascii_lowercase + string.ascii_uppercase + string.digits
tn = ''
for i in xrange(8):
tn += cns[random.randint(0,len(cns)-1)]
return tn
tmpdir = '/tmp/test_crypto'+tmpname()
tmpfiles = ['cmdhistory', 'config.json', 'data.db']
def stub_files():
enter_tmpdir()
for sf in tmpfiles:
with os.fdopen(os.open(sf, os.O_CREAT, 0o0600), 'r'):
pass
def enter_tmpdir():
if not os.path.isdir(tmpdir):
os.mkdir(tmpdir)
os.chdir(tmpdir)
def test_decrypt_tmpdir():
enter_tmpdir()
crypt().decrypt_project()
assert os.path.isdir(os.path.join(os.getcwd(), '../crypt'))
def test_decrypt_copy_files():
enter_tmpdir()
stub_files()
crypt().decrypt_project()
for tf in tmpfiles:
assert os.path.isfile(tf)
Loading…
Cancel
Save