Removed old compress and crypto plugins
Got rid of the old plugin structure for the crypto and compress features.
This commit is contained in:
parent
5be69b205d
commit
870d2abbe8
5 changed files with 0 additions and 293 deletions
|
@ -1,89 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import crochet
|
|
||||||
import glob
|
|
||||||
import pappyproxy
|
|
||||||
|
|
||||||
import zipfile
|
|
||||||
import tarfile
|
|
||||||
|
|
||||||
# This is a gross hack, please help
|
|
||||||
bz2 = None
|
|
||||||
try:
|
|
||||||
import bz2
|
|
||||||
except:
|
|
||||||
print "BZ2 not installed on your system"
|
|
||||||
|
|
||||||
from base64 import b64encode, b64decode
|
|
||||||
from os import getcwd, sep, path, urandom
|
|
||||||
from pappyproxy.plugins.misc import CryptoCompressUtils as ccu
|
|
||||||
|
|
||||||
def compress_project():
|
|
||||||
if bz2:
|
|
||||||
tar_project()
|
|
||||||
else:
|
|
||||||
zip_project()
|
|
||||||
|
|
||||||
def decompress_project():
|
|
||||||
if bz2:
|
|
||||||
untar_project()
|
|
||||||
else:
|
|
||||||
unzip_project()
|
|
||||||
|
|
||||||
def zip_project():
|
|
||||||
"""
|
|
||||||
Zip project files
|
|
||||||
|
|
||||||
Using append mode (mode='a') will create a zip archive
|
|
||||||
if none exists in the project.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
zf = zipfile.ZipFile(ZIPFILE, mode="a")
|
|
||||||
project_files = ccu.get_project_files()
|
|
||||||
for pf in project_files:
|
|
||||||
zf.write(pf)
|
|
||||||
zf.close()
|
|
||||||
except e:
|
|
||||||
raise PappyException("Error creating the zipfile", e)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def unzip_project():
|
|
||||||
"""
|
|
||||||
Extract project files from decrypted zip archive.
|
|
||||||
Initially checks the zip archive's magic number and
|
|
||||||
attempts to extract pappy.json to validate integrity
|
|
||||||
of the zipfile.
|
|
||||||
"""
|
|
||||||
if not zipfile.is_zipfile(ZIPFILE):
|
|
||||||
raise PappyException("Project archive corrupted.")
|
|
||||||
|
|
||||||
zf = zipfile.ZipFile(ZIPFILE)
|
|
||||||
|
|
||||||
try:
|
|
||||||
zf.extract("config.json")
|
|
||||||
except e:
|
|
||||||
raise PappyException("Project archive contents corrupted. Error: ", e)
|
|
||||||
|
|
||||||
zf.extractall()
|
|
||||||
|
|
||||||
def tar_project():
|
|
||||||
if tarfile.is_tarfile(BZ2FILE):
|
|
||||||
archive = tarfile.open(ccu.BZ2FILE, 'w:bz2')
|
|
||||||
project_files = ccu.get_project_files()
|
|
||||||
|
|
||||||
# Read files line by line to accomodate larger files, e.g. the project database
|
|
||||||
for pf in project_files:
|
|
||||||
archive.add(pf)
|
|
||||||
archive.close()
|
|
||||||
|
|
||||||
def untar_project():
|
|
||||||
if tarfile.is_tarfile(BZ2FILE):
|
|
||||||
# Attempt to read the first 16 bytes of the archive
|
|
||||||
# Raise exception if there is a failure
|
|
||||||
project_files = ccu.get_project_files()
|
|
||||||
try:
|
|
||||||
with tarfile.open(BZ2FILE, "r:bz2") as archive:
|
|
||||||
for pf in project_files:
|
|
||||||
archive.add(pf)
|
|
||||||
except e:
|
|
||||||
raise PappyException("Project archive contents corrupted. Error: ", e
|
|
|
@ -1,182 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import crochet
|
|
||||||
import glob
|
|
||||||
import pappyproxy
|
|
||||||
|
|
||||||
import scrypt
|
|
||||||
import twisted
|
|
||||||
|
|
||||||
from base64 import b64encode, b64decode
|
|
||||||
from cryptography import Fernet
|
|
||||||
from os import getcwd, sep, path, remove, urandom
|
|
||||||
from pappyproxy.plugins import compress
|
|
||||||
from pappyproxy.plugins.misc import CryptoCompressUtils as ccu
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt_project(passwd):
|
|
||||||
"""
|
|
||||||
Compress and encrypt the project files, deleting clear-text files afterwards
|
|
||||||
"""
|
|
||||||
# Derive the key
|
|
||||||
key = crypto_ramp_up(passwd)
|
|
||||||
# Instantiate the crypto module
|
|
||||||
fern = Fernet(key)
|
|
||||||
|
|
||||||
compress.compress_project()
|
|
||||||
archive = None
|
|
||||||
if path.is_file(ZIPFILE):
|
|
||||||
archive = open(ccu.ZIPFILE, 'rb')
|
|
||||||
else:
|
|
||||||
archive = open(ccu.BZ2FILE, 'rb')
|
|
||||||
archive_crypt = open(ccu.CRYPTFILE, 'wb')
|
|
||||||
|
|
||||||
# Encrypt the archive read as a bytestring
|
|
||||||
crypt_token = fern.encrypt(archive)
|
|
||||||
archive_crypt.write(crypt_token)
|
|
||||||
|
|
||||||
# Delete clear-text files
|
|
||||||
delete_clear_files()
|
|
||||||
|
|
||||||
def decrypt_project(passwd):
|
|
||||||
"""
|
|
||||||
Decompress and decrypt the project files
|
|
||||||
"""
|
|
||||||
# Derive the key
|
|
||||||
key = crypto_ramp_up(passwd)
|
|
||||||
fern = Fernet(key)
|
|
||||||
archive_crypt = open(ccu.CRYPTFILE, 'rb')
|
|
||||||
archive = fern.decrypt(archive_crypt)
|
|
||||||
compress.decompress_project()
|
|
||||||
delete_crypt_files()
|
|
||||||
|
|
||||||
|
|
||||||
def crypto_ramp_up(passwd):
|
|
||||||
salt = ""
|
|
||||||
if path.isfile(ccu.SALTFILE):
|
|
||||||
salt = get_salt()
|
|
||||||
else:
|
|
||||||
salt = create_salt()
|
|
||||||
key = derive_key(passwd, salt)
|
|
||||||
return key
|
|
||||||
|
|
||||||
def delete_clear_files():
|
|
||||||
"""
|
|
||||||
Deletes all clear-text files left in the project directory.
|
|
||||||
"""
|
|
||||||
project_files = ccu.get_project_files()
|
|
||||||
for pf in project_files:
|
|
||||||
os.remove(pf)
|
|
||||||
|
|
||||||
def delete_crypt_files():
|
|
||||||
"""
|
|
||||||
Deletes all encrypted-text files in the project directory.
|
|
||||||
Forces generation of new salt after opening and closing the project.
|
|
||||||
Adds security in the case of a one-time compromise of the system.
|
|
||||||
"""
|
|
||||||
os.remove(ccu.SALTFILE)
|
|
||||||
os.remove(ccu.CRYPTFILE)
|
|
||||||
|
|
||||||
def create_salt():
|
|
||||||
salt = b64encode(urandom(16))
|
|
||||||
salt_file = open(ccu.SALTFILE, 'wb')
|
|
||||||
salt_file.write(salt)
|
|
||||||
salt_file.close()
|
|
||||||
return salt
|
|
||||||
|
|
||||||
def get_salt():
|
|
||||||
try:
|
|
||||||
salt_file = open(ccu.SALTFILE, 'rb')
|
|
||||||
salt = b64decode(salt_file.readline())
|
|
||||||
except:
|
|
||||||
raise PappyException("Unable to read pappy.salt")
|
|
||||||
return salt
|
|
||||||
|
|
||||||
def get_password():
|
|
||||||
"""
|
|
||||||
Retrieve password from the user. Raise an exception if the
|
|
||||||
password is not capable of base64 encoding.
|
|
||||||
"""
|
|
||||||
encode_passwd = ""
|
|
||||||
try:
|
|
||||||
passwd = raw_input("Enter a password: ")
|
|
||||||
encode_passwd = b64encode(passwd.encode("utf-8"))
|
|
||||||
except:
|
|
||||||
raise PappyException("Invalid password, try again")
|
|
||||||
return encode_passwd
|
|
||||||
|
|
||||||
def derive_key(passwd, salt):
|
|
||||||
"""
|
|
||||||
Derive a key sufficient for use as a cryptographic key
|
|
||||||
used to encrypt the project (currently: cryptography.Fernet).
|
|
||||||
|
|
||||||
cryptography.Fernet utilizes AES-CBC-128, requiring a 32-byte key.
|
|
||||||
Parameter notes from the py-scrypt source-code:
|
|
||||||
https://bitbucket.org/mhallin/py-scrypt/
|
|
||||||
|
|
||||||
Compute scrypt(password, salt, N, r, p, buflen).
|
|
||||||
|
|
||||||
The parameters r, p, and buflen must satisfy r * p < 2^30 and
|
|
||||||
buflen <= (2^32 - 1) * 32. The parameter N must be a power of 2
|
|
||||||
greater than 1. N, r and p must all be positive.
|
|
||||||
|
|
||||||
Notes for Python 2:
|
|
||||||
- `password` and `salt` must be str instances
|
|
||||||
- The result will be a str instance
|
|
||||||
|
|
||||||
Notes for Python 3:
|
|
||||||
- `password` and `salt` can be both str and bytes. If they are str
|
|
||||||
instances, they wil be encoded with utf-8.
|
|
||||||
- The result will be a bytes instance
|
|
||||||
|
|
||||||
Exceptions raised:
|
|
||||||
- TypeError on invalid input
|
|
||||||
- scrypt.error if scrypt failed
|
|
||||||
"""
|
|
||||||
|
|
||||||
derived_key = ""
|
|
||||||
try:
|
|
||||||
dkey = scrypt.hash(passwd, salt, bufflen=32)
|
|
||||||
except e:
|
|
||||||
raise PappyException("Error deriving the key: ", e)
|
|
||||||
return derived_key
|
|
||||||
|
|
||||||
|
|
||||||
@crochet.wait_for(timeout=None)
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def cryptocmd(line):
|
|
||||||
"""
|
|
||||||
Encrypt/Decrypt local project directory
|
|
||||||
Usage: pappy -e
|
|
||||||
Details:
|
|
||||||
Pappy will create a compressed archive of local project files.
|
|
||||||
|
|
||||||
The archive file is encrypted using the cryptography.Fernet module,
|
|
||||||
a user-supplied password and the scrypt key-derivation function.
|
|
||||||
|
|
||||||
cryptography.Fernet uses AES-CBC-128 with HMAC256. This is merely
|
|
||||||
a starting point, and any help implementing a stronger crypto-system
|
|
||||||
is very welcome. Development is geared toward using
|
|
||||||
AES-256-GCM as the AEAD encryption mode to eliminate the need for Fernet and HMAC256.
|
|
||||||
SCrypt will still be used as the key derivation function until a public-key encryption
|
|
||||||
scheme is developed.
|
|
||||||
|
|
||||||
See Encryption section of README.md for more information.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if isinstance(line, str):
|
|
||||||
args = crochet.split(line)
|
|
||||||
## Encryption mode (Encrypt=0, Decrypt=1)
|
|
||||||
## Set internally depending if plugin is called during pappy startup or shutdown
|
|
||||||
mode = args[0]
|
|
||||||
|
|
||||||
## Request the pasword from the user
|
|
||||||
passwd = get_passwd()
|
|
||||||
|
|
||||||
if mode == ccu.ENCRYPT:
|
|
||||||
encrypt_project(passwd)
|
|
||||||
elif mode == ccu.DECRYPT:
|
|
||||||
decrypt_project(passwd)
|
|
||||||
else:
|
|
||||||
raise PappyException("Incorrect crypto mode")
|
|
||||||
|
|
|
@ -201,25 +201,3 @@ def load_cmds(cmd):
|
||||||
cmd.add_aliases([
|
cmd.add_aliases([
|
||||||
#('rpy', ''),
|
#('rpy', ''),
|
||||||
])
|
])
|
||||||
|
|
||||||
class CryptoCompressUtils():
|
|
||||||
# Constants
|
|
||||||
ENCRYPT = 0
|
|
||||||
DECRYPT = 1
|
|
||||||
PROJECT_PATH = getcwd() + sep
|
|
||||||
ZIPFILE = PROJECT_PATH + "pappy.zip"
|
|
||||||
BZ2FILE = PROJECT_PATH + "pappy.bz2"
|
|
||||||
CRYPTFILE = ""
|
|
||||||
if path.isfile(ZIPFILE):
|
|
||||||
CRYPTFILE = ZIPFILE + ".crypt"
|
|
||||||
elsif path.isfile(BZ2FILE):
|
|
||||||
CRYPTFILE = BZ2FILE + ".crypt"
|
|
||||||
SALTFILE = PROJECT_PATH + "pappy.salt"
|
|
||||||
|
|
||||||
def get_project_files():
|
|
||||||
file_glob = glob.glob('*')
|
|
||||||
pp = PROJECT_PATH
|
|
||||||
project_files = [pp+f for f in file_glob if path.isfile(pp+f)]
|
|
||||||
project_files.remove(SALTFILE)
|
|
||||||
project_files.remove(CRYPTFILE)
|
|
||||||
return project_files
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue