def encrypt(file): gpg_home = find_gpg_keys() if ( gpg_home == ''): print 'GPG keys not found' sys.exit(1) gpg = GPG(gnupghome=gpg_home, use_agent=True) public_keys = gpg.list_keys() key_id = public_keys[0]['keyid'] if ( os.path.isfile(file)): if ( file.endswith('.gpg')): print file + ' is already encrypted' else: stream = open(file, "rb") status = gpg.encrypt_file(stream, key_id, passphrase='default_key', armor=False, always_trust=True, output=file+'.gpg', symmetric=False) stream.close() if ( status.ok): os.remove(file) print file , ' successfully encrypted' elif (os.path.isdir(file)): for root, dirs, files in os.walk(file, topdown=True): for name in files: current_file = (os.path.join(root, name)) if ( current_file.endswith('.gpg') ): print current_file + ' : is already encrypted' else: stream = open(current_file, "rb") status = gpg.encrypt_file(stream, key_id, armor=True, always_trust=True, symmetric=False, output=current_file+'.gpg') stream.close() if ( status.ok ): os.remove(current_file) print current_file + ' successfully encrypted' else: print 'ERROR, file or directory not found'
def execute(self): gpg_home = os.path.join(os.path.expanduser('~'), '.gnupg/') default_recpipient = os.environ['DEFAULT_RECIPIENT'] if not default_recpipient: self.fm.notify( 'DEFAULT_RECIPIENT environment variable must be set') return gpg = GPG(gpgbinary='/usr/bin/gpg', gnupghome=gpg_home) paths = [ os.path.basename(f.path) for f in self.fm.thistab.get_selection() ] for p in paths: if os.path.isdir(p): new_p = self.tardir(p) run(['rm', '-rf', p]) p = new_p with open(p, 'rb') as f: enc = gpg.encrypt_file(f, default_recpipient) with open(p + '.gpg', 'wb+') as out: out.write(enc.data) if os.path.isfile(p): os.remove(p)
def __call__(self): fileName = as_human_readable(self.get_chosen_files()[0]) gpg = GPG() default_recipient = self._get_default_recipient() recipient, ok = show_prompt('Recipient', default=default_recipient) with open(fileName, 'rb') as f: status = gpg.encrypt_file(f, recipients=[recipient], output=fileName + '.gpg') show_alert('Status: ' + status.status)
def encrypt_file(gpg: gnupg.GPG, targer_folder: str): configuration_kwargs = utils.get_configuratation( path=os.path.join( targer_folder, 'configuration' ) ) value = _get_decryption(configuration_kwargs=configuration_kwargs) gpg.import_keys(value) keys = gpg.list_keys() gpg.trust_keys( keys.fingerprints, 'TRUST_ULTIMATE' ) decrypted_filepaths = utils.get_files( path=os.path.join( targer_folder, 'decrypted_files' ) ) encrypted_path = os.path.join( targer_folder, 'encrypted_files' ) for decryped_file in decrypted_filepaths: base_name = __set_file_name(path=decryped_file) logger.info(f'encrypting file {base_name}') output_file = os.path.join( encrypted_path, base_name ) with open(decryped_file, 'rb') as connection: status = gpg.encrypt_file( file=connection, recipients=keys.fingerprints, output=output_file, ) logger.info(f'encrypting done') if not status.ok: logger.info(f'{status.stderr}') else: logger.info(f'Status [{status.status}]')
def decrypt_files(path, gpg: gnupg.GPG): for files in os.listdir(path): actual_path = path + "/" + files if os.path.isfile(actual_path): if files.endswith(".gpg"): logger.debug(f"decrypting: {actual_path}") with open(actual_path, "rb") as reader: print(gpg.decrypt_file(reader, passphrase=__passphrase__, output=actual_path).status) logger.debug(f"encrypting: {actual_path}") with open(actual_path, "rb") as reader: print(gpg.encrypt_file(reader, recipients=__newkeyid__, output=actual_path).status) else: decrypt_files(actual_path, gpg)
def encrypt_file(filename): cfg = ConfigFromJSON(section='gpg') if not op.exists(filename): raise ValueError('File {} not exisit'.format(filename)) gpg = GPG() target = ".".join([filename, 'gpg']) with open(filename, 'rb') as f: enc = gpg.encrypt_file(f, None, symmetric=True, passphrase=cfg.passphrase, output=target) if not enc.ok: raise RuntimeError(enc.status) return target
def createciphermsgs_gpg(jt65msgcount, stegmsg, recipient, verbose=False): # Performs the actual GPG encryption ciphermsgs = [] while len(stegmsg) % 8: stegmsg += " " gpg = GPG() stegstream = io.StringIO(unicode(stegmsg)) cipherdata = gpg.encrypt_file(stegstream, recipient) if cipherdata == "": print "You must set the recipient's trust level to -something- in your keyring before we can encrypt the message" sys.exit(0) cipherlist = list(bytearray(str(cipherdata))) if verbose: print "Cipher list: " + str(cipherlist) if jt65msgcount * 8 < len(cipherlist): print( "Length of hidden message exceeds capacity of number of valid JT65 messages provided") sys.exit(0) # Is the total length too big to fit into our max number of packets? if len(cipherlist) > MAX_MULTI_PACKET_STEG_BYTES_GPG: print("Length of hidden message exceeds capacity of multi-packet steg") sys.exit(0) totalpackets = len(cipherlist) / 8 createciphermsgs_packer_other( totalpackets, ciphermsgs, cipherlist, verbose) return ciphermsgs
class PGPContext(object): def __init__(self, tempdirprefix=None): if tempdirprefix is None: tempdir = tempfile.mkdtemp() else: tempdir = tempfile.mkdtemp(prefix=tempdirprefix) try: self.gnupg = GPG(gnupghome=tempdir, options=['--trust-model', 'always']) self.gnupg.encoding = "UTF-8" except OSError as excep: log.err("Critical, OS error in operating with GnuPG home: %s", excep) raise except Exception as excep: log.err("Unable to instance PGP object: %s" % excep) raise def load_key(self, key): """ @param key @return: a dict with the expiration date and the key fingerprint """ try: import_result = self.gnupg.import_keys(key) except Exception as excep: log.err("Error in PGP import_keys: %s", excep) raise errors.InputValidationError if not import_result.fingerprints: raise errors.InputValidationError fingerprint = import_result.fingerprints[0] # looking if the key is effectively reachable try: all_keys = self.gnupg.list_keys() except Exception as excep: log.err("Error in PGP list_keys: %s", excep) raise errors.InputValidationError expiration = datetime.utcfromtimestamp(0) for k in all_keys: if k['fingerprint'] == fingerprint: if k['expires']: expiration = datetime.utcfromtimestamp(int(k['expires'])) break return {'fingerprint': fingerprint, 'expiration': expiration} def encrypt_file(self, key_fingerprint, input_file, output_path): """ Encrypt a file with the specified PGP key """ encrypted_obj = self.gnupg.encrypt_file(input_file, key_fingerprint, output=output_path) if not encrypted_obj.ok: raise errors.InputValidationError return encrypted_obj, os.stat(output_path).st_size def encrypt_message(self, key_fingerprint, plaintext): """ Encrypt a text message with the specified key """ encrypted_obj = self.gnupg.encrypt(plaintext, key_fingerprint) if not encrypted_obj.ok: raise errors.InputValidationError return str(encrypted_obj) def __del__(self): try: shutil.rmtree(self.gnupg.gnupghome) except Exception as excep: log.err("Unable to clean temporary PGP environment: %s: %s", self.gnupg.gnupghome, excep)
class gpg(object): """ module to wrap the gnupg library and gpg binary """ def __init__(self, folder_path=None, binary_path=None): # ugly but working if binary_path is None: binary_path = join(project_base, "gpg", "gpg.exe") if not isfile(binary_path): binary_path = join(project_base, 'gpg') if not isfile(binary_path): binary_path = find_executable('gpg') if not isfile(binary_path): raise RuntimeError('gpg not found') self.gpg = GPG( binary_path, # gpgbinary folder_path, # gnupghome verbose=False, options=["--allow-non-selfsigned-uid"]) def get_key(self, fingerprint, private, passphrase): """ returns the key belonging to the fingerprint given. if 'private' is True, the private key is returned. If 'private' is False, the public key will be returned. """ key = self.gpg.export_keys(fingerprint, private, armor=False, passphrase=passphrase) return b64encode(key) def add_keypair(self, public_key, private_key, site, user, passphrase): """ add a keypair into the gpg key database """ try: result1 = self.gpg.import_keys(b64decode(public_key)) result2 = self.gpg.import_keys(b64decode(private_key)) except TypeError as error: getLogger(__name__).critical("add_keypair TypeError " + str(error)) # make sure this is a key _pair_ try: assert result1.fingerprints[0] == result2.fingerprints[0] except (IndexError, AssertionError) as error: getLogger(__name__).exception( 'add_keypair IndexError/AssertionError: ' + str(error)) return None fingerprint = result1.fingerprints[0] if self.is_passphrase_valid(passphrase=passphrase, fingerprint=fingerprint): old_fingerprint = self.get_fingerprint(site, user) if not old_fingerprint: sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?)" database_execute(sql, (site, user, fingerprint)) else: sql = "UPDATE keys SET SITE=? WHERE fingerprint=?" database_execute(sql, (site, old_fingerprint)) if fingerprint != old_fingerprint: getLogger(__name__).warn('updating %s fingerprint to %s' % (user, fingerprint)) return fingerprint else: return None def add_public_key(self, site, user, public_key): """ add a public key into the gpg key database """ try: result1 = self.gpg.import_keys(b64decode(public_key)) fingerprint = result1.fingerprints[0] sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?)" database_execute(sql, (site, user, fingerprint)) return fingerprint except TypeError as error: getLogger(__name__).critical("add_public_key TypeError " + str(error)) except DatabaseError as error: getLogger(__name__).critical("add_public_key DatabaseError " + str(error)) def is_passphrase_valid(self, passphrase, label=None, user=None, fingerprint=None): if not fingerprint: fingerprint = self.get_fingerprint(label, user) sign_result = self.gpg.sign("test", keyid=fingerprint, passphrase=passphrase) return sign_result.data != '' def generate(self, passphrase, site, user): """ Generate a new 2048 bit GPG key and add it to the gpg manager. """ data = self.gpg.gen_key_input(key_length=2048, passphrase=passphrase) dat = self.gpg.gen_key(data) fingerprint = dat.fingerprint sql = "INSERT INTO keys (site, user, fingerprint) VALUES (?, ?, ?);" database_execute(sql, (site, user, fingerprint)) return fingerprint def get_fingerprint(self, site, user): sql = "select fingerprint from keys where site = ? and user = ?" result = database_execute(sql, (site, user)) if not len(result): return None return result[0][0] def has_key(self, site, user): """ Check whether a key is present for a certain site and user """ return self.get_fingerprint(site, user) is None def encrypt(self, data, site, user, armor=False): """ encrypt data for user at site. """ fingerprint = self.get_fingerprint(site, user) cryptdata = self.gpg.encrypt_file(StringIO(data), fingerprint, always_trust=True, armor=armor) return str(cryptdata) def decrypt(self, data, passphrase): """ decrypt data received from site. """ datafile = StringIO(data) result = self.gpg.decrypt_file(datafile, passphrase=passphrase, always_trust=True) return str(result) @staticmethod def add_pkcs7_padding(contents): # Input strings must be a multiple of the segment size 16 bytes in length segment_size = 16 # calculate how much padding is needed old_contents_length = len(contents) next_mult = old_contents_length + (segment_size - old_contents_length % segment_size) getLogger(__name__).debug( 'old contents length %s || new contents length %s' % (old_contents_length, next_mult)) # do the padding padding_byte = chr(next_mult - old_contents_length) contents = contents.ljust(next_mult, padding_byte) return contents @staticmethod def remove_pkcs7_padding(contents): """ Remove PKCS#7 padding bytes >>> gpg.remove_pkcs7_padding('some_content'.ljust(16, chr(4))) 'some_content' >>> gpg.remove_pkcs7_padding('some_content') 'some_content' >>> gpg.remove_pkcs7_padding('') '' :param contents: :return: contents without padding """ if len(contents) < 1: getLogger(__name__).debug( 'contents is empty. No PKCS#7 padding removed') return contents bytes_to_remove = ord(contents[-1]) # will work up to 255 bytes # check if contents have valid PKCS#7 padding if bytes_to_remove > 1 and contents[-2] != contents[-1]: getLogger(__name__).debug('no PKCS#7 padding detected') return contents getLogger(__name__).debug('removing %s bytes of PKCS#7 padding' % bytes_to_remove) return contents[0:(len(contents) - bytes_to_remove)]
class GLBGPG: """ GPG has not a dedicated class, because one of the function is called inside a transact, and I'm not quite confident on creating an object that operates on the filesystem knowing that would be run also on the Storm cycle. """ def __init__(self, receiver_desc): """ every time is needed, a new keyring is created here. """ if receiver_desc.has_key('gpg_key_status') and \ receiver_desc['gpg_key_status'] != Receiver._gpg_types[1]: # Enabled log.err( "Requested GPG initialization for a receiver without GPG configured! %s" % receiver_desc['username']) raise Exception("Requested GPG init for user without GPG [%s]" % receiver_desc['username']) try: temp_gpgroot = os.path.join(GLSetting.gpgroot, "%s" % xeger(r'[A-Za-z0-9]{8}')) os.makedirs(temp_gpgroot, mode=0700) self.gpgh = GPG(gnupghome=temp_gpgroot, options=['--trust-model', 'always']) except Exception as excep: log.err("Unable to instance GPG object: %s" % excep) raise excep self.receiver_desc = receiver_desc log.debug("GPG object initialized for receiver %s" % receiver_desc['username']) def sanitize_gpg_string(self, received_gpgasc): """ @param received_gpgasc: A gpg armored key @return: Sanitized string or raise InvalidInputFormat This function validate the integrity of a GPG key """ lines = received_gpgasc.split("\n") sanitized = "" start = 0 if not len(lines[start]): start += 1 if lines[start] != '-----BEGIN PGP PUBLIC KEY BLOCK-----': raise errors.InvalidInputFormat("GPG invalid format") else: sanitized += lines[start] + "\n" i = 0 while i < len(lines): # the C language as left some archetypes in my code # [ITA] https://www.youtube.com/watch?v=7jI4DnRJP3k i += 1 try: if len(lines[i]) < 2: continue except IndexError: continue main_content = re.compile( r"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$", re.UNICODE) base64only = main_content.findall(lines[i]) if len(base64only) == 1: sanitized += str(base64only[0]) + "\n" # this GPG/PGP format it's different from the common base64 ? dunno if len(lines[i]) == 5 and lines[i][0] == '=': sanitized += str(lines[i]) + "\n" if lines[i] == '-----END PGP PUBLIC KEY BLOCK-----': sanitized += lines[i] + "\n" return sanitized raise errors.InvalidInputFormat("Malformed PGP key block") def validate_key(self, armored_key): """ @param armored_key: @return: True or False, True only if a key is effectively importable and listed. """ # or raise InvalidInputFormat sanitized_gpgasc = self.sanitize_gpg_string(armored_key) try: key = self.gpgh.import_keys(sanitized_gpgasc) except Exception as excep: log.err("Error in GPG import_keys: %s" % excep) return False # Error reported in stderr may just be warning, this is because is not raise an exception here # if self.ke.stderr: # log.err("Receiver %s in uploaded GPG key has raise and alarm:\n< %s >" % # (self.receiver_desc['username'], (self.ke.stderr.replace("\n", "\n "))[:-3])) if not (hasattr(key, 'results') and len(key.results) >= 1 and key.results[0].has_key('fingerprint')): log.err("User error: unable to import GPG key in the keyring") return False # else, the key has been loaded and we extract info about that: self.fingerprint = key.results[0]['fingerprint'] # looking if the key is effectively reachable try: all_keys = self.gpgh.list_keys() except Exception as excep: log.err("Error in GPG list_keys: %s" % excep) return False self.keyinfo = u"" for key in all_keys: if key['fingerprint'] == self.fingerprint: self.keyinfo += "Key length %s" % key['length'] try: for uid in key['uids']: self.keyinfo += "\n\t%s" % uid except Exception as excep: log.err("Error in GPG key format/properties: %s" % excep) return False if not len(self.keyinfo): log.err("Key apparently imported but unable to be extracted info") return False return True def encrypt_file(self, plainpath, filestream, output_path): """ @param gpg_key_armor: @param plainpath: @return: """ if not self.validate_key(self.receiver_desc['gpg_key_armor']): raise errors.GPGKeyInvalid encrypt_obj = self.gpgh.encrypt_file( filestream, str(self.receiver_desc['gpg_key_fingerprint'])) if not encrypt_obj.ok: # continue here if is not ok log.err("Falure in encrypting file %s %s (%s)" % (plainpath, self.receiver_desc['username'], self.receiver_desc['gpg_key_fingerprint'])) log.err(encrypt_obj.stderr) raise errors.GPGKeyInvalid log.debug("Encrypting for %s (%s) file %s (%d bytes)" % (self.receiver_desc['username'], self.receiver_desc['gpg_key_fingerprint'], plainpath, len(str(encrypt_obj)))) encrypted_path = os.path.join( os.path.abspath(output_path), "gpg_encrypted-%s" % xeger(r'[A-Za-z0-9]{8}')) if os.path.isfile(encrypted_path): log.err("Unexpected unpredictable unbelievable error! %s" % encrypted_path) raise errors.InternalServerError( "File conflict in GPG encrypted output") try: with open(encrypted_path, "w+") as f: f.write(str(encrypt_obj)) return encrypted_path, len(str(encrypt_obj)) except Exception as excep: log.err("Error in writing GPG file output: %s (%s) bytes %d" % (excep.message, encrypted_path, len(str(encrypt_obj)))) raise errors.InternalServerError("Error in writing [%s]" % excep.message) def encrypt_message(self, plaintext): """ @param plaindata: An arbitrary long text that would be encrypted @param receiver_desc: The output of globaleaks.handlers.admin.admin_serialize_receiver() dictionary. It contain the fingerprint of the Receiver PUBKEY @return: The unicode of the encrypted output (armored) """ if not self.validate_key(self.receiver_desc['gpg_key_armor']): raise errors.GPGKeyInvalid # This second argument may be a list of fingerprint, not just one encrypt_obj = self.gpgh.encrypt( plaintext, str(self.receiver_desc['gpg_key_fingerprint'])) if not encrypt_obj.ok: # else, is not .ok log.err("Falure in encrypting %d bytes for %s (%s)" % (len(plaintext), self.receiver_desc['username'], self.receiver_desc['gpg_key_fingerprint'])) log.err(encrypt_obj.stderr) raise errors.GPGKeyInvalid log.debug( "Encrypting for %s (%s) %d byte of plain data (%d cipher output)" % (self.receiver_desc['username'], self.receiver_desc['gpg_key_fingerprint'], len(plaintext), len(str(encrypt_obj)))) return str(encrypt_obj) def destroy_environment(self): try: shutil.rmtree(self.gpgh.gnupghome) except Exception as excep: log.err("Unable to clean temporary GPG environment: %s: %s" % (self.gpgh.gnupghome, excep))
class PGPContext(object): """ PGP does not have a dedicated class, because one of the function is called inside a transact. I'm not confident creating an object that operates on the filesystem knowing that would be run also on the Storm cycle. """ def __init__(self, tempdirprefix=None): """ every time is needed, a new keyring is created here. """ if tempdirprefix is None: tempdir = tempfile.mkdtemp() else: tempdir = tempfile.mkdtemp(prefix=tempdirprefix) try: gpgbinary = 'gpg' if os.path.exists('/usr/bin/gpg1'): gpgbinary = 'gpg1' self.gnupg = GPG(gpgbinary=gpgbinary, gnupghome=tempdir, options=['--trust-model', 'always']) self.gnupg.encoding = "UTF-8" except OSError as excep: log.err("Critical, OS error in operating with GnuPG home: %s", excep) raise except Exception as excep: log.err("Unable to instance PGP object: %s" % excep) raise def load_key(self, key): """ @param key @return: a dict with the expiration date and the key fingerprint """ try: import_result = self.gnupg.import_keys(key) except Exception as excep: log.err("Error in PGP import_keys: %s", excep) raise errors.InputValidationError if not import_result.fingerprints: raise errors.InputValidationError fingerprint = import_result.fingerprints[0] # looking if the key is effectively reachable try: all_keys = self.gnupg.list_keys() except Exception as excep: log.err("Error in PGP list_keys: %s", excep) raise errors.InputValidationError expiration = datetime.utcfromtimestamp(0) for k in all_keys: if k['fingerprint'] == fingerprint: if k['expires']: expiration = datetime.utcfromtimestamp(int(k['expires'])) break return {'fingerprint': fingerprint, 'expiration': expiration} def encrypt_file(self, key_fingerprint, input_file, output_path): """ Encrypt a file with the specified PGP key """ encrypted_obj = self.gnupg.encrypt_file(input_file, str(key_fingerprint), output=output_path) if not encrypted_obj.ok: raise errors.InputValidationError return encrypted_obj, os.stat(output_path).st_size def encrypt_message(self, key_fingerprint, plaintext): """ Encrypt a text message with the specified key """ encrypted_obj = self.gnupg.encrypt(plaintext, str(key_fingerprint)) if not encrypted_obj.ok: raise errors.InputValidationError return str(encrypted_obj) def __del__(self): try: shutil.rmtree(self.gnupg.gnupghome) except Exception as excep: log.err("Unable to clean temporary PGP environment: %s: %s", self.gnupg.gnupghome, excep)
class GLBPGP(object): """ PGP has not a dedicated class, because one of the function is called inside a transact, and I'm not quite confident on creating an object that operates on the filesystem knowing that would be run also on the Storm cycle. """ def __init__(self): """ every time is needed, a new keyring is created here. """ try: temp_pgproot = os.path.join(GLSettings.pgproot, "%s" % generateRandomKey(8)) os.makedirs(temp_pgproot, mode=0700) self.gnupg = GPG(gnupghome=temp_pgproot, options=['--trust-model', 'always']) self.gnupg.encoding = "UTF-8" except OSError as ose: log.err("Critical, OS error in operating with GnuPG home: %s" % ose) raise except Exception as excep: log.err("Unable to instance PGP object: %s" % excep) raise def load_key(self, key): """ @param key: @return: True or False, True only if a key is effectively importable and listed. """ try: import_result = self.gnupg.import_keys(key) except Exception as excep: log.err("Error in PGP import_keys: %s" % excep) raise errors.PGPKeyInvalid if len(import_result.fingerprints) == 0: raise errors.PGPKeyInvalid fingerprint = import_result.fingerprints[0] # looking if the key is effectively reachable try: all_keys = self.gnupg.list_keys() except Exception as excep: log.err("Error in PGP list_keys: %s" % excep) raise errors.PGPKeyInvalid expiration = datetime.utcfromtimestamp(0) for key in all_keys: if key['fingerprint'] == fingerprint: if key['expires']: expiration = datetime.utcfromtimestamp(int(key['expires'])) break return { 'fingerprint': fingerprint, 'expiration': expiration, } def encrypt_file(self, key_fingerprint, input_file, output_path): """ Encrypt a file with the specified PGP key """ encrypted_obj = self.gnupg.encrypt_file(input_file, str(key_fingerprint), output=output_path) if not encrypted_obj.ok: raise errors.PGPKeyInvalid return encrypted_obj, os.stat(output_path).st_size def encrypt_message(self, key_fingerprint, plaintext): """ Encrypt a text message with the specified key """ encrypted_obj = self.gnupg.encrypt(plaintext, str(key_fingerprint)) if not encrypted_obj.ok: raise errors.PGPKeyInvalid return str(encrypted_obj) def destroy_environment(self): try: shutil.rmtree(self.gnupg.gnupghome) except Exception as excep: log.err("Unable to clean temporary PGP environment: %s: %s" % (self.gnupg.gnupghome, excep))
from ftplib import FPT # Create instance and set gpg working directory gpg = GPG(gnupghome=".gpg") # import an existing public key with open("mykey.asc", 'r') as fp: key_data = fp.read() import_status = gpg.import_keys(key_data) print("ok: {}".format(import_status.results["ok"])) print("text: {}".format(import_status.results["text"])) # Encrypt a file using the public key. with open("plain.txt", 'rb') as fp: encrypted_file = "encrypted.asc" encrypt_status = gpg.encrypt_file(fp, recipients=import_status.fingerprints, always_trust=True, output=encrypted_file) print("ok {}".format(encrypt_status.ok)) print("text: {}".format(encrypt_status.text)) print("stderr: {}".format(encrypt_status.stderr)) # FTP the file with FTP("ftp.somehost.com") as ftp: ftp.connect("a_username", "a_password") fp = open(encrypted_file, 'rb') ftp.storbinary("STOR {}".format(encrypted_file), fp) ftp.quit() fp.close()
class PGPContext(object): def __init__(self, tempdirprefix=None): if tempdirprefix is None: tempdir = tempfile.mkdtemp() else: tempdir = tempfile.mkdtemp(prefix=tempdirprefix) try: gpgbinary='gpg' if os.path.exists('/usr/bin/gpg1'): gpgbinary='gpg1' self.gnupg = GPG(gpgbinary=gpgbinary, gnupghome=tempdir, options=['--trust-model', 'always']) self.gnupg.encoding = "UTF-8" except OSError as excep: log.err("Critical, OS error in operating with GnuPG home: %s", excep) raise except Exception as excep: log.err("Unable to instance PGP object: %s" % excep) raise def load_key(self, key): """ @param key @return: a dict with the expiration date and the key fingerprint """ try: import_result = self.gnupg.import_keys(key) except Exception as excep: log.err("Error in PGP import_keys: %s", excep) raise errors.InputValidationError if not import_result.fingerprints: raise errors.InputValidationError fingerprint = import_result.fingerprints[0] # looking if the key is effectively reachable try: all_keys = self.gnupg.list_keys() except Exception as excep: log.err("Error in PGP list_keys: %s", excep) raise errors.InputValidationError expiration = datetime.utcfromtimestamp(0) for k in all_keys: if k['fingerprint'] == fingerprint: if k['expires']: expiration = datetime.utcfromtimestamp(int(k['expires'])) break return { 'fingerprint': fingerprint, 'expiration': expiration } def encrypt_file(self, key_fingerprint, input_file, output_path): """ Encrypt a file with the specified PGP key """ encrypted_obj = self.gnupg.encrypt_file(input_file, str(key_fingerprint), output=output_path) if not encrypted_obj.ok: raise errors.InputValidationError return encrypted_obj, os.stat(output_path).st_size def encrypt_message(self, key_fingerprint, plaintext): """ Encrypt a text message with the specified key """ encrypted_obj = self.gnupg.encrypt(plaintext, str(key_fingerprint)) if not encrypted_obj.ok: raise errors.InputValidationError return str(encrypted_obj) def __del__(self): try: shutil.rmtree(self.gnupg.gnupghome) except Exception as excep: log.err("Unable to clean temporary PGP environment: %s: %s", self.gnupg.gnupghome, excep)
class GLBPGP(object): """ PGP has not a dedicated class, because one of the function is called inside a transact, and I'm not quite confident on creating an object that operates on the filesystem knowing that would be run also on the Storm cycle. """ def __init__(self): """ every time is needed, a new keyring is created here. """ try: temp_pgproot = os.path.join(GLSettings.pgproot, "%s" % xeger(r'[A-Za-z0-9]{8}')) os.makedirs(temp_pgproot, mode=0700) self.pgph = GPG(gnupghome=temp_pgproot, options=['--trust-model', 'always']) self.pgph.encoding = "UTF-8" except OSError as ose: log.err("Critical, OS error in operating with GnuPG home: %s" % ose) raise except Exception as excep: log.err("Unable to instance PGP object: %s" % excep) raise def load_key(self, key): """ @param key: @return: True or False, True only if a key is effectively importable and listed. """ try: import_result = self.pgph.import_keys(key) except Exception as excep: log.err("Error in PGP import_keys: %s" % excep) raise errors.PGPKeyInvalid if len(import_result.fingerprints) != 1: raise errors.PGPKeyInvalid fingerprint = import_result.fingerprints[0] # looking if the key is effectively reachable try: all_keys = self.pgph.list_keys() except Exception as excep: log.err("Error in PGP list_keys: %s" % excep) raise errors.PGPKeyInvalid info = u"" expiration = datetime.utcfromtimestamp(0) for key in all_keys: if key['fingerprint'] == fingerprint: if key['expires']: expiration = datetime.utcfromtimestamp(int(key['expires'])) exp_date = datetime_to_day_str(expiration) else: exp_date = u'Never' info += "Key length: %s\n" % key['length'] info += "Key expiration: %s\n" % exp_date try: for uid in key['uids']: info += "\t%s\n" % uid except Exception as excep: log.err("Error in PGP key format/properties: %s" % excep) raise errors.PGPKeyInvalid break if not len(info): log.err("Key apparently imported but unable to reload it") raise errors.PGPKeyInvalid ret = { 'fingerprint': fingerprint, 'expiration': expiration, 'info': info } return ret def encrypt_file(self, key_fingerprint, plainpath, filestream, output_path): """ @param pgp_key_public: @param plainpath: @return: """ encrypt_obj = self.pgph.encrypt_file(filestream, str(key_fingerprint)) if not encrypt_obj.ok: raise errors.PGPKeyInvalid log.debug("Encrypting for key %s file %s (%d bytes)" % (key_fingerprint, plainpath, len(str(encrypt_obj)))) encrypted_path = os.path.join(os.path.abspath(output_path), "pgp_encrypted-%s" % xeger(r'[A-Za-z0-9]{16}')) try: with open(encrypted_path, "w+") as f: f.write(str(encrypt_obj)) return encrypted_path, len(str(encrypt_obj)) except Exception as excep: log.err("Error in writing PGP file output: %s (%s) bytes %d" % (excep.message, encrypted_path, len(str(encrypt_obj)) )) raise errors.InternalServerError("Error in writing [%s]" % excep.message) def encrypt_message(self, key_fingerprint, plaintext): """ @param plaindata: An arbitrary long text that would be encrypted @param receiver_desc: The output of globaleaks.handlers.admin.admin_serialize_receiver() dictionary. It contain the fingerprint of the Receiver PUBKEY @return: The unicode of the encrypted output (armored) """ # This second argument may be a list of fingerprint, not just one encrypt_obj = self.pgph.encrypt(plaintext, str(key_fingerprint)) if not encrypt_obj.ok: raise errors.PGPKeyInvalid log.debug("Encrypting for key %s %d byte of plain data (%d cipher output)" % (key_fingerprint, len(plaintext), len(str(encrypt_obj)))) return str(encrypt_obj) def destroy_environment(self): try: shutil.rmtree(self.pgph.gnupghome) except Exception as excep: log.err("Unable to clean temporary PGP environment: %s: %s" % (self.pgph.gnupghome, excep))
class GLBPGP(object): """ PGP has not a dedicated class, because one of the function is called inside a transact, and I'm not quite confident on creating an object that operates on the filesystem knowing that would be run also on the Storm cycle. """ def __init__(self): """ every time is needed, a new keyring is created here. """ try: temp_pgproot = os.path.join(GLSettings.pgproot, "%s" % rstr.xeger(r'[A-Za-z0-9]{8}')) os.makedirs(temp_pgproot, mode=0700) self.pgph = GPG(gnupghome=temp_pgproot, options=['--trust-model', 'always']) self.pgph.encoding = "UTF-8" except OSError as ose: log.err("Critical, OS error in operating with GnuPG home: %s" % ose) raise except Exception as excep: log.err("Unable to instance PGP object: %s" % excep) raise def load_key(self, key): """ @param key: @return: True or False, True only if a key is effectively importable and listed. """ try: import_result = self.pgph.import_keys(key) except Exception as excep: log.err("Error in PGP import_keys: %s" % excep) raise errors.PGPKeyInvalid if len(import_result.fingerprints) != 1: raise errors.PGPKeyInvalid fingerprint = import_result.fingerprints[0] # looking if the key is effectively reachable try: all_keys = self.pgph.list_keys() except Exception as excep: log.err("Error in PGP list_keys: %s" % excep) raise errors.PGPKeyInvalid info = u"" expiration = datetime.utcfromtimestamp(0) for key in all_keys: if key['fingerprint'] == fingerprint: if key['expires']: expiration = datetime.utcfromtimestamp(int(key['expires'])) exp_date = datetime_to_day_str(expiration) else: exp_date = u'Never' info += "Key length: %s\n" % key['length'] info += "Key expiration: %s\n" % exp_date try: for uid in key['uids']: info += "\t%s\n" % uid except Exception as excep: log.err("Error in PGP key format/properties: %s" % excep) raise errors.PGPKeyInvalid break if not len(info): log.err("Key apparently imported but unable to reload it") raise errors.PGPKeyInvalid return { 'fingerprint': fingerprint, 'expiration': expiration, 'info': info } def encrypt_file(self, key_fingerprint, plainpath, filestream, output_path): """ @param pgp_key_public: @param plainpath: @return: """ encrypt_obj = self.pgph.encrypt_file(filestream, str(key_fingerprint)) if not encrypt_obj.ok: raise errors.PGPKeyInvalid log.debug("Encrypting for key %s file %s (%d bytes)" % (key_fingerprint, plainpath, len(str(encrypt_obj)))) encrypted_path = os.path.join(os.path.abspath(output_path), "pgp_encrypted-%s" % rstr.xeger(r'[A-Za-z0-9]{16}')) try: with open(encrypted_path, "w+") as f: f.write(str(encrypt_obj)) return encrypted_path, len(str(encrypt_obj)) except Exception as excep: log.err("Error in writing PGP file output: %s (%s) bytes %d" % (excep.message, encrypted_path, len(str(encrypt_obj)) )) raise errors.InternalServerError("Error in writing [%s]" % excep.message) def encrypt_message(self, key_fingerprint, plaintext): """ @param plaindata: An arbitrary long text that would be encrypted @param receiver_desc: The output of globaleaks.handlers.admin.admin_serialize_receiver() dictionary. It contain the fingerprint of the Receiver PUBKEY @return: The unicode of the encrypted output (armored) """ # This second argument may be a list of fingerprint, not just one encrypt_obj = self.pgph.encrypt(plaintext, str(key_fingerprint)) if not encrypt_obj.ok: raise errors.PGPKeyInvalid log.debug("Encrypting for key %s %d byte of plain data (%d cipher output)" % (key_fingerprint, len(plaintext), len(str(encrypt_obj)))) return str(encrypt_obj) def destroy_environment(self): try: shutil.rmtree(self.pgph.gnupghome) except Exception as excep: log.err("Unable to clean temporary PGP environment: %s: %s" % (self.pgph.gnupghome, excep))
class GLBGPG(object): """ GPG has not a dedicated class, because one of the function is called inside a transact, and I'm not quite confident on creating an object that operates on the filesystem knowing that would be run also on the Storm cycle. """ def __init__(self): """ every time is needed, a new keyring is created here. """ try: temp_gpgroot = os.path.join(GLSetting.gpgroot, "%s" % xeger(r'[A-Za-z0-9]{8}')) os.makedirs(temp_gpgroot, mode=0700) self.gpgh = GPG(gnupghome=temp_gpgroot, options=['--trust-model', 'always']) self.gpgh.encoding = "UTF-8" except Exception as excep: log.err("Unable to instance GPG object: %s" % excep) raise excep def sanitize_gpg_string(self, key): """ @param key: A pgp armored key @return: Sanitized string or raise InvalidInputFormat This function validate the integrity of a GPG key """ lines = key.split("\n") sanitized = "" start = 0 if not len(lines[start]): start += 1 if lines[start] != '-----BEGIN PGP PUBLIC KEY BLOCK-----': raise errors.InvalidInputFormat("GPG invalid format") else: sanitized += lines[start] + "\n" i = 0 while i < len(lines): # the C language has left some archetypes in my code # [ITA] https://www.youtube.com/watch?v=7jI4DnRJP3k i += 1 try: if len(lines[i]) < 2: continue except IndexError: continue main_content = re.compile( r"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$", re.UNICODE) base64only = main_content.findall(lines[i]) if len(base64only) == 1: sanitized += str(base64only[0]) + "\n" # this GPG/PGP format it's different from the common base64 ? dunno if len(lines[i]) == 5 and lines[i][0] == '=': sanitized += str(lines[i]) + "\n" if lines[i] == '-----END PGP PUBLIC KEY BLOCK-----': sanitized += lines[i] + "\n" return sanitized raise errors.InvalidInputFormat("Malformed PGP key block") def load_key(self, key): """ @param key: @return: True or False, True only if a key is effectively importable and listed. """ try: sanitized_key = self.sanitize_gpg_string(key) import_result = self.gpgh.import_keys(sanitized_key) except Exception as excep: log.err("Error in GPG import_keys: %s" % excep) raise errors.GPGKeyInvalid if len(import_result.fingerprints) != 1: raise errors.GPGKeyInvalid fingerprint = import_result.fingerprints[0] # looking if the key is effectively reachable try: all_keys = self.gpgh.list_keys() except Exception as excep: log.err("Error in GPG list_keys: %s" % excep) raise errors.GPGKeyInvalid info = u"" expiration = datetime.utcfromtimestamp(0) for key in all_keys: if key['fingerprint'] == fingerprint: if key['expires']: expiration = datetime.utcfromtimestamp(int(key['expires'])) exp_date = datetime_to_day_str(expiration) else: exp_date = u'Never' info += "Key length: %s\n" % key['length'] info += "Key expiration: %s\n" % exp_date try: for uid in key['uids']: info += "\t%s\n" % uid except Exception as excep: log.err("Error in GPG key format/properties: %s" % excep) raise errors.GPGKeyInvalid break if not len(info): log.err("Key apparently imported but unable to reload it") raise errors.GPGKeyInvalid ret = { 'fingerprint': fingerprint, 'expiration': expiration, 'info': info } return ret def encrypt_file(self, key_fingerprint, plainpath, filestream, output_path): """ @param gpg_key_armor: @param plainpath: @return: """ encrypt_obj = self.gpgh.encrypt_file(filestream, str(key_fingerprint)) if not encrypt_obj.ok: raise errors.GPGKeyInvalid log.debug("Encrypting for key %s file %s (%d bytes)" % (key_fingerprint, plainpath, len(str(encrypt_obj)))) encrypted_path = os.path.join( os.path.abspath(output_path), "gpg_encrypted-%s" % xeger(r'[A-Za-z0-9]{8}')) try: with open(encrypted_path, "w+") as f: f.write(str(encrypt_obj)) return encrypted_path, len(str(encrypt_obj)) except Exception as excep: log.err("Error in writing GPG file output: %s (%s) bytes %d" % (excep.message, encrypted_path, len(str(encrypt_obj)))) raise errors.InternalServerError("Error in writing [%s]" % excep.message) def encrypt_message(self, key_fingerprint, plaintext): """ @param plaindata: An arbitrary long text that would be encrypted @param receiver_desc: The output of globaleaks.handlers.admin.admin_serialize_receiver() dictionary. It contain the fingerprint of the Receiver PUBKEY @return: The unicode of the encrypted output (armored) """ # This second argument may be a list of fingerprint, not just one encrypt_obj = self.gpgh.encrypt(plaintext, str(key_fingerprint)) if not encrypt_obj.ok: raise errors.GPGKeyInvalid log.debug( "Encrypting for key %s %d byte of plain data (%d cipher output)" % (key_fingerprint, len(plaintext), len(str(encrypt_obj)))) return str(encrypt_obj) def destroy_environment(self): try: shutil.rmtree(self.gpgh.gnupghome) except Exception as excep: log.err("Unable to clean temporary GPG environment: %s: %s" % (self.gpgh.gnupghome, excep))
class GLBGPG: """ GPG has not a dedicated class, because one of the function is callend inside a transact, and I'm not quite confident on creating an object that operates on the filesystem knowing that would be run also on the Storm cycle. """ def __init__(self, receiver_desc): """ every time is needed, a new keyring is created here. """ atfork() if receiver_desc.has_key('gpg_key_status') and \ receiver_desc['gpg_key_status'] != Receiver._gpg_types[1]: # Enabled log.err("Requested GPG initialization for a receiver without GPG configured! %s" % receiver_desc['username']) raise Exception("Requested GPG init for user without GPG [%s]" % receiver_desc['username']) try: temp_gpgroot = os.path.join(GLSetting.gpgroot, "%s" % random.randint(0, 0xFFFF) ) os.makedirs(temp_gpgroot, mode=0700) self.gpgh = GPG(gnupghome=temp_gpgroot, options="--trust-model always") except Exception as excep: log.err("Unable to instance GPG object: %s" % excep) raise excep self.receiver_desc = receiver_desc log.debug("GPG object initialized for receiver %s" % receiver_desc['username']) def sanitize_gpg_string(self, received_gpgasc): """ @param received_gpgasc: A gpg armored key @return: Sanitized string or raise InvalidInputFormat This function validate the integrity of a GPG key """ lines = received_gpgasc.split("\n") sanitized = "" start = 0 if not len(lines[start]): start += 1 if lines[start] != '-----BEGIN PGP PUBLIC KEY BLOCK-----': raise errors.InvalidInputFormat("GPG invalid format") else: sanitized += lines[start] + "\n" i = 0 while i < len(lines): # the C language as left some archetypes in my code # [ITA] https://www.youtube.com/watch?v=7jI4DnRJP3k i += 1 try: if len(lines[i]) < 2: continue except IndexError: continue main_content = re.compile( r"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" , re.UNICODE) base64only = main_content.findall(lines[i]) if len(base64only) == 1: sanitized += str(base64only[0]) + "\n" # this GPG/PGP format it's different from the common base64 ? dunno if len(lines[i]) == 5 and lines[i][0] == '=': sanitized += str(lines[i]) + "\n" if lines[i] == '-----END PGP PUBLIC KEY BLOCK-----': sanitized += lines[i] + "\n" return sanitized raise errors.InvalidInputFormat("Malformed PGP key block") def validate_key(self, armored_key): """ @param armored_key: @return: True or False, True only if a key is effectively importable and listed. """ # or raise InvalidInputFormat sanitized_gpgasc = self.sanitize_gpg_string(armored_key) try: self.ke = self.gpgh.import_keys(sanitized_gpgasc) except Exception as excep: log.err("Error in GPG import_keys: %s" % excep) return False # Error reported in stderr may just be warning, this is because is not raise an exception here # if self.ke.stderr: # log.err("Receiver %s in uploaded GPG key has raise and alarm:\n< %s >" % # (self.receiver_desc['username'], (self.ke.stderr.replace("\n", "\n "))[:-3])) if not (hasattr(self.ke, 'results') and len(self.ke.results) == 1 and self.ke.results[0].has_key('fingerprint')): log.err("User error: unable to import GPG key in the keyring") return False # else, the key has been loaded and we extract info about that: self.fingerprint = self.ke.results[0]['fingerprint'] # looking if the key is effectively reachable try: all_keys = self.gpgh.list_keys() except Exception as excep: log.err("Error in GPG list_keys: %s" % excep) return False self.keyinfo = u"" for key in all_keys: if key['fingerprint'] == self.fingerprint: self.keyinfo += "Key length %s" % key['length'] try: for uid in key['uids']: self.keyinfo += "\n\t%s" % uid except Exception as excep: log.err("Error in GPG key format/properties: %s" % excep) return False if not len(self.keyinfo): log.err("Key apparently imported but unable to be extracted info") return False return True def encrypt_file(self, plainpath, filestream, output_path): """ @param gpg_key_armor: @param plainpath: @return: """ if not self.validate_key(self.receiver_desc['gpg_key_armor']): raise errors.GPGKeyInvalid encrypt_obj = self.gpgh.encrypt_file(filestream, str(self.receiver_desc['gpg_key_fingerprint'])) if not encrypt_obj.ok: # continue here if is not ok log.err("Falure in encrypting file %s %s (%s)" % ( plainpath, self.receiver_desc['username'], self.receiver_desc['gpg_key_fingerprint']) ) log.err(encrypt_obj.stderr) raise errors.GPGKeyInvalid log.debug("Encrypting for %s (%s) file %s (%d bytes)" % (self.receiver_desc['username'], self.receiver_desc['gpg_key_fingerprint'], plainpath, len(str(encrypt_obj))) ) encrypted_path = os.path.join( os.path.abspath(output_path), "gpg_encrypted-%d-%d" % (random.randint(0, 0xFFFF), random.randint(0, 0xFFFF))) if os.path.isfile(encrypted_path): log.err("Unexpected unpredictable unbelievable error! %s" % encrypted_path) raise errors.InternalServerError("File conflict in GPG encrypted output") try: with open(encrypted_path, "w+") as f: f.write(str(encrypt_obj)) return encrypted_path, len(str(encrypt_obj)) except Exception as excep: log.err("Error in writing GPG file output: %s (%s) bytes %d" % (excep.message, encrypted_path, len(str(encrypt_obj)) )) raise errors.InternalServerError("Error in writing [%s]" % excep.message ) def encrypt_message(self, plaintext): """ @param plaindata: An arbitrary long text that would be encrypted @param receiver_desc: The output of globaleaks.handlers.admin.admin_serialize_receiver() dictionary. It contain the fingerprint of the Receiver PUBKEY @return: The unicode of the encrypted output (armored) """ if not self.validate_key(self.receiver_desc['gpg_key_armor']): raise errors.GPGKeyInvalid # This second argument may be a list of fingerprint, not just one encrypt_obj = self.gpgh.encrypt(plaintext, str(self.receiver_desc['gpg_key_fingerprint']) ) if not encrypt_obj.ok: # else, is not .ok log.err("Falure in encrypting %d bytes for %s (%s)" % (len(plaintext), self.receiver_desc['username'], self.receiver_desc['gpg_key_fingerprint']) ) log.err(encrypt_obj.stderr) raise errors.GPGKeyInvalid log.debug("Encrypting for %s (%s) %d byte of plain data (%d cipher output)" % (self.receiver_desc['username'], self.receiver_desc['gpg_key_fingerprint'], len(plaintext), len(str(encrypt_obj))) ) return str(encrypt_obj) def destroy_environment(self): try: shutil.rmtree(self.gpgh.gnupghome) except Exception as excep: log.err("Unable to clean temporary GPG environment: %s: %s" % (self.gpgh.gnupghome, excep))