You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/Crypto/library/cryptor.py

168 lines
8.7 KiB

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from Naked.toolshed.shell import muterun
from Naked.toolshed.system import file_size, stdout, stderr
from shellescape import quote
# ------------------------------------------------------------------------------
# Cryptor class
# performs gpg encryption of one or more files
# ------------------------------------------------------------------------------
class Cryptor(object):
"""performs gpg encryption of one or more files"""
def __init__(self, passphrase):
self.command_default = "gpg -z 1 --batch --force-mdc --cipher-algo AES256 -o "
self.command_nocompress = "gpg -z 0 --batch --force-mdc --cipher-algo AES256 -o "
self.command_maxcompress = "gpg -z 7 --batch --force-mdc --cipher-algo AES256 -o "
self.command_default_armored = "gpg -z 1 --armor --batch --force-mdc --cipher-algo AES256 -o "
self.command_nocompress_armored = "gpg -z 0 --armor --batch --force-mdc --cipher-algo AES256 -o "
self.command_maxcompress_armored = "gpg -z 7 --armor --batch --force-mdc --cipher-algo AES256 -o "
self.passphrase = passphrase
self.common_binaries = set(['.7z', '.gz', '.aac', '.app', '.avi', '.azw', '.bz2', '.deb', '.doc', '.dmg', '.exe', '.flv', '.gif', '.jar', '.jpg', '.mov', '.mp3', '.mp4', '.odt', '.oga', '.ogg', '.ogm', '.pdf', '.pkg', '.png', '.ppt', '.pps', '.psd', '.rar', '.rpm', '.tar', '.tif', '.wav', '.wma', '.wmv', '.xls', '.zip', '.aiff', '.docx', '.epub', '.flac', '.mpeg', '.jpeg', '.pptx', '.xlsx'])
self.common_text = set(['.c', '.h', '.m', '.cc', '.js', '.pl', '.py', '.rb', '.sh', '.cpp', '.css', '.csv', '.php', '.rss', '.txt', '.xml', '.yml', '.java', '.json', '.html', '.yaml'])
# ------------------------------------------------------------------------------
# PUBLIC methods
# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# encrypt_file : file encryption method
# ------------------------------------------------------------------------------
def encrypt_file(self, inpath, force_nocompress=False, force_compress=False, armored=False, checksum=False):
"""public method for single file encryption with optional compression, ASCII armored formatting, and file hash digest generation"""
if armored:
if force_compress:
command_stub = self.command_maxcompress_armored
elif force_nocompress:
command_stub = self.command_nocompress_armored
else:
if self._is_compress_filetype(inpath):
command_stub = self.command_default_armored
else:
command_stub = self.command_nocompress_armored
else:
if force_compress:
command_stub = self.command_maxcompress
elif force_nocompress:
command_stub = self.command_nocompress
else:
if self._is_compress_filetype(inpath):
command_stub = self.command_default
else:
command_stub = self.command_nocompress
encrypted_outpath = self._create_outfilepath(inpath)
system_command = command_stub + encrypted_outpath + " --passphrase " + quote(self.passphrase) + " --symmetric " + quote(inpath)
try:
response = muterun(system_command)
# check returned status code
if response.exitcode == 0:
stdout(encrypted_outpath + " was generated from " + inpath)
if checksum: # add a SHA256 hash digest of the encrypted file - requested by user --hash flag in command
from crypto.library import hash
encrypted_file_hash = hash.generate_hash(encrypted_outpath)
if len(encrypted_file_hash) == 64:
stdout("SHA256 hash digest for " + encrypted_outpath + " :")
stdout(encrypted_file_hash)
else:
stdout("Unable to generate a SHA256 hash digest for the file " + encrypted_outpath)
else:
stderr(response.stderr, 0)
stderr("Encryption failed")
sys.exit(1)
except Exception as e:
stderr("There was a problem with the execution of gpg. Encryption failed. Error: [" + str(e) + "]")
sys.exit(1)
# ------------------------------------------------------------------------------
# encrypt_files : multiple file encryption
# ------------------------------------------------------------------------------
def encrypt_files(self, file_list, force_nocompress=False, force_compress=False, armored=False, checksum=False):
"""public method for multiple file encryption with optional compression, ASCII armored formatting, and file hash digest generation"""
for the_file in file_list:
self.encrypt_file(the_file, force_nocompress, force_compress, armored, checksum)
# ------------------------------------------------------------------------------
# cleanup : overwrite the passphrase in memory
# ------------------------------------------------------------------------------
def cleanup(self):
"""public method that overwrites user passphrase in memory"""
self.passphrase = ""
# ------------------------------------------------------------------------------
# PRIVATE methods
# ------------------------------------------------------------------------------
def _create_outfilepath(self, inpath):
"""private method that generates the crypto saved file path string with a .crypt file type"""
return inpath + '.crypt'
def _is_compress_filetype(self, inpath):
"""private method that performs magic number and size check on file to determine whether to compress the file"""
# check for common file type suffixes in order to avoid the need for file reads to check magic number for binary vs. text file
if self._is_common_binary(inpath):
return False
elif self._is_common_text(inpath):
return True
else:
# files > 10kB get checked for compression (arbitrary decision to skip compression on small files)
the_file_size = file_size(inpath)
if the_file_size > 10240:
if the_file_size > 512000: # seems to be a break point at ~ 500kb where file compression offset by additional file read, so limit tests to files > 500kB
try:
system_command = "file --mime-type -b " + quote(inpath)
response = muterun(system_command)
if response.stdout[0:5] == "text/": # check for a text file mime type
return True # appropriate size, appropriate file mime type
else:
return False # appropriate size, inappropriate file mime type
except Exception:
return False
else:
return True # if file size is < 500kB, skip the additional file read and just go with compression
else:
return False # below minimum size to consider compression, do not compress
def _is_common_binary(self, inpath):
"""private method to compare file path mime type to common binary file types"""
# make local variables for the available char numbers in the suffix types to be tested
two_suffix = inpath[-3:]
three_suffix = inpath[-4:]
four_suffix = inpath[-5:]
# test for inclusion in the instance variable common_binaries (defined in __init__)
if two_suffix in self.common_binaries:
return True
elif three_suffix in self.common_binaries:
return True
elif four_suffix in self.common_binaries:
return True
else:
return False
def _is_common_text(self, inpath):
"""private method to compare file path mime type to common text file types"""
# make local variables for the available char numbers in the suffix types to be tested
one_suffix = inpath[-2:]
two_suffix = inpath[-3:]
three_suffix = inpath[-4:]
four_suffix = inpath[-5:]
# test for inclusion in the instance variable common_text (defined in __init__)
if one_suffix in self.common_text:
return True
elif two_suffix in self.common_text:
return True
elif three_suffix in self.common_text:
return True
elif four_suffix in self.common_text:
return True
else:
return False