def gen_pass_query(password, user_id, path_to_user_folder, name): print('1') val_old = '/' part = name.split('/') if not path.isdir(path_to_user_folder + '/' + '/'.join(part[:-1])): makedirs(path_to_user_folder + '/' + '/'.join(part[:-1])) gpg = GPG() gpg.encrypt( password, recipients=['user_' + user_id], output=path_to_user_folder + '/' + name + '.gpg', )
def encrypt_archive(config, workspace, passcode): narrate("Encrypting the archive") with cd(workspace): run('tar -cf archive.tgz archive', 'soEW') with open('archive.tgz', 'rb') as f: cleartext = f.read() gpg = GPG() encrypted = gpg.encrypt( cleartext, recipients=None, symmetric=True, passphrase=str(passcode), ) if encrypted.ok: with open('archive.tgz.gpg', 'w') as f: f.write(str(encrypted)) else: raise EncryptionFailed(encrypted) rm('archive.tgz', 'archive') script = workspace / 'decrypt.sh' script.write_text('''\ #!/bin/sh # Decrypts the archive. gpg -d -o - archive.tgz.gpg | tar xvf - ''') chmod(0o700, script, workspace / 'archive.tgz.gpg') narrate(f"Local archive '{workspace.name}' created.")
def send_mail(self, subject, body): if self.gpg_key: with TemporaryDirectory() as tmp_dir: gpg = GPG(homedir=tmp_dir) key = gpg.import_keys(self.gpg_key) body = str(gpg.encrypt(body, *key.fingerprints)) send_mail(subject, body, settings.EMAIL_ADDRESS, [self.email])
def finish_auth_pass(message, bot): t_str = 'test_ur_crappy_password_str' decrypt = None try: gpg = GPG() encrypt = gpg.encrypt(t_str, recipients='user_' + str(message.chat.id)) decrypt = gpg.decrypt(str(encrypt), passphrase=str(message.text)) system('echo RELOADAGENT | gpg-connect-agent') except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) result_available.set() if str(decrypt) == t_str: global pas msg = bot.send_message(message.chat.id, 'Вы аутентифицировались.') pas = str(message.text) del_mess(msg, bot, 4) result_available.set() else: msg = bot.send_message(message.chat.id, 'Пароль не верен.') del_mess(msg, bot, 4) result_available.set()
class reqPGP(object): def __init__(self, path=None): self.gpg = GPG(gpgbinary=('../gpg.exe' if osName == 'nt' else 'gpg')) if not path: try: self.path = environ["HOME"] + '/' except KeyError: self.path = environ["HOMEPATH"] + '\\' else: if path[-1] != '\\' and osName == 'nt': path += '\\' elif path[-1] != '/' and osName == 'posix': path += '/' self.path = path def genKey(self, account, passphrase): input_data = self.gpg.gen_key_input( name_email=account, passphrase=passphrase) self.gpg.gen_key(input_data) def encryptFile(self, account, data): encryptedData = str(self.gpg.encrypt(data, account)) with open(self.path + '.' + account + '.req', 'w') as f: f.write(encryptedData) def decryptFile(self, account, passphrase): with open(self.path + '.' + account + '.req', 'rb') as f: decryptedData = str(self.gpg.decrypt_file(f, passphrase=passphrase)) return decryptedData def deleteKey(self, keyId): self.gpg.delete_keys(keyId, True) self.gpg.delete_keys(keyId)
def _encrypt(self, plain): # test if we have public keys for all recipients available_recipients = [] keys = [] for key in Key.objects.all(): keys.append(key) available_recipients.extend(key.addresses.split(', ')) logger.debug("available_recipients: %s", available_recipients) if not all(recipient in available_recipients for recipient in self.recipients()): logger.error( "Public key not present for at least one of these recipients: %s", self.recipients()) raise GPGException( "Public key not present for at least one recipient") # encryption with TemporaryDirectory() as temp_dir: gpg = GPG(gnupghome=temp_dir) for key in keys: gpg.import_keys(key.key) res = gpg.encrypt(plain, self.recipients(), always_trust=True) if not res: handle_gpg_error(res, 'encryption') return smart_text(res)
def finish_clone_pass(message, bot, path_to_user_folder): t_str = 'test_ur_crappy_password_str' decrypt = None try: gpg = GPG() encrypt = gpg.encrypt(t_str, recipients='user_'+str(message.chat.id)) decrypt = gpg.decrypt(str(encrypt), passphrase=message.text) system('echo RELOADAGENT | gpg-connect-agent') except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 8) return if str(decrypt) == t_str: try: with open(path_to_user_folder+'/user_data/Nothing.txt', 'w') as f: f.write(message.text) msg = bot.send_message(message.chat.id, 'Пароль сохранен.', reply_markup = types.ReplyKeyboardRemove(selective=False)) del_mess(msg, bot, 8) return except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.', reply_markup = types.ReplyKeyboardRemove(selective=False)) del_mess(msg, bot, 8) return else: msg = bot.send_message(message.chat.id, 'Пароль не верен.') msg_handler = bot.send_message(message.chat.id, 'Введите пароль от нового ключа, я его сохраню.', reply_markup = types.ReplyKeyboardRemove(selective=False)) bot.register_next_step_handler(msg_handler, lambda msg: finish_clone_pass(msg, bot, path_to_user_folder))
class reqPGP(object): def __init__(self, path=None): self.gpg = GPG(gpgbinary=('../gpg.exe' if osName == 'nt' else 'gpg')) if not path: try: self.path = environ["HOME"] + '/' except KeyError: self.path = environ["HOMEPATH"] + '\\' else: if path[-1] != '\\' and osName == 'nt': path += '\\' elif path[-1] != '/' and osName == 'posix': path += '/' self.path = path def genKey(self, account, passphrase): input_data = self.gpg.gen_key_input(name_email=account, passphrase=passphrase) self.gpg.gen_key(input_data) def encryptFile(self, account, data): encryptedData = str(self.gpg.encrypt(data, account)) with open(self.path + '.' + account + '.req', 'w') as f: f.write(encryptedData) def decryptFile(self, account, passphrase): with open(self.path + '.' + account + '.req', 'rb') as f: decryptedData = str(self.gpg.decrypt_file(f, passphrase=passphrase)) return decryptedData def deleteKey(self, keyId): self.gpg.delete_keys(keyId, True) self.gpg.delete_keys(keyId)
def rm_and_create_file(message, bot, file, name): try: gpg = GPG() remove(file + '.gpg') gpg.encrypt( message.text, recipients=['user_' + str(message.chat.id)], output=file + '.gpg', ) msg = bot.send_message(message.chat.id, 'Запись ' + name + ' изменена.') del_mess(msg, bot, 2) return except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return
def touch_pass_query(message, bot, way, name): val_old = '/' part = name.split('/') try: if not path.isdir(way + '/' + '/'.join(part[:-1])): makedirs(way + '/' + '/'.join(part[:-1])) gpg = GPG() gpg.encrypt( message.text, recipients=['user_' + str(message.chat.id)], output=way + '/' + name + '.gpg', ) msg = bot.send_message(message.chat.id, 'Запись ' + name + ' добавлена.') del_mess(msg, bot, 4) return except: msg = bot.send_message(message.chat.id, 'Произошла ошибка.') del_mess(msg, bot, 4) return
def send_mail(subject, body_text, addr_from, addr_to, fail_silently=False, attachments=None, body_html=None): """ Sends a multipart email containing text and html versions which are encrypted for each recipient that has a valid gpg key installed. """ # Allow for a single address to be passed in. if not hasattr(addr_to, "__iter__"): addr_to = [addr_to] # Obtain a list of the recipients that have gpg keys installed. valid_key_addresses = [] if USE_GNUPG: queryset = Address.objects.filter(address__in=addr_to) valid_key_addresses = queryset.values_list("address", flat=True) # Create the gpg object. if valid_key_addresses: gpg = GPG(gnupghome=GNUPG_HOME) gpg_kwargs = {} if ALWAYS_TRUST: gpg_kwargs.update({'always_trust':ALWAYS_TRUST}) # Encrypts body if recipient has a gpg key installed. encrypt_if_key = lambda body, addr: (body if addr not in valid_key_addresses else unicode(gpg.encrypt(body, addr, **gpg_kwargs))) # Load attachments and create name/data tuples. attachments_parts = [] if attachments is not None: for attachment in attachments: with open(attachment, "rb") as f: attachments_parts.append((basename(attachment), f.read())) # Send emails. for addr in addr_to: msg = EmailMultiAlternatives(subject, encrypt_if_key(body_text, addr), addr_from, [addr]) if body_html is not None: msg.attach_alternative(encrypt_if_key(body_html, addr), "text/html") for parts in attachments_parts: msg.attach(parts[0]+'.asc' if ADD_EXTENSION else parts[0], encrypt_if_key(parts[1], addr)) msg.send(fail_silently=fail_silently)
def write_key(path, key_data, gpg_bin, gpg_opts): """Encrypt and write a single key file. :param str path: The path to the key to decrypt. :param str gpg_bin: The path to the gpg binary. :param list gpg_opts: The options for gpg. """ gpg = GPG(gpgbinary=gpg_bin, options=gpg_opts) gpg_recipients = _get_gpg_recipients(path) # pass always ends it's files with an endline if not key_data.endswith('\n'): key_data += '\n' key_data_enc = gpg.encrypt(key_data, gpg_recipients).data with open(path, 'wb') as key_file: key_file.write(key_data_enc)
class Vault(object): def __init__(self): self.vault = {} self._gpg = GPG() self._file_descriptor = None self.passphrase = None def reload(self): if None in (self._file_descriptor, self.passphrase): raise RuntimeError('Cannot reload before calling .load()') self.load(self._file_descriptor, self.passphrase) def load(self, file_descriptor, passphrase): self._file_descriptor = file_descriptor self.passphrase = passphrase self._file_descriptor.seek(0) json_ = self._gpg.decrypt_file(self._file_descriptor, passphrase=self.passphrase) self.vault = json.loads(str(json_)) def save(self, file_descriptor=None, passphrase=None): if file_descriptor is not None: self._file_descriptor = file_descriptor if passphrase is not None: self.passphrase = passphrase self._file_descriptor.seek(0) json_ = json.dumps(self.vault) encrypted = self._gpg.encrypt(json_, False, passphrase=self.passphrase, symmetric=True) self._file_descriptor.write(str(encrypted)) def __getitem__(self, key): return self.vault[key] def get(self, name, default=None): return self.vault.get(name, default) def __setitem__(self, key, value): self.vault[key] = value def __delitem__(self, key): del self._vault[key] def list(self): return sorted(self._vault.keys())
def _encrypt(self, plain): # test if we have public keys for all recipients available_recipients = [] keys = [] for key in Key.objects.all(): keys.append(key) available_recipients.extend(key.addresses.split(', ')) logger.debug("available_recipients: %s", available_recipients) if not all(recipient in available_recipients for recipient in self.recipients()): logger.error("Public key not present for at least one of these recipients: %s", self.recipients()) raise GPGException("Public key not present for at least one recipient") # encryption with TemporaryDirectory() as temp_dir: gpg = GPG(gnupghome=temp_dir) for key in keys: gpg.import_keys(key.key) res = gpg.encrypt(plain, self.recipients(), always_trust=True) if not res: handle_gpg_error(res, 'encryption') return smart_text(res)
def send(recipient, email, *words): ''' encrypt, sign, and send a private message to recipient `recipient` is the 'nick' (nickname) of the user to whom you wish to send the message. `email` is not necessarily an email address, but is used to find the GPG key of the recipient. use `-` instead of email to send plain text ''' if len(words) > 1 or isinstance(words[0], str): text = ' '.join(words).encode() else: text = words[0] # as when called by `publish` logging.debug('words: %s', words) encoded = None if email != '-': gpg = GPG() logging.debug('message before encrypting: %s', text) encrypted = gpg.encrypt( text, # pylint: disable=no-member [email], sign=True, armor=False) logging.debug('encrypted: %r...', encrypted.data[:64]) encoded = b58encode(encrypted.data).decode() logging.debug('encoded: %s', encoded) if text and not encoded: if email == '-' or os.getenv('KB_SEND_PLAINTEXT_OK'): logging.warning('encryption %s, sending plaintext', 'bypassed' if email == '-' else 'failed') encoded = text.decode() else: logging.warning('encryption failed, run with ' 'KB_SEND_PLAINTEXT_OK=1 to send anyway') logging.warning('setting message to "(encryption failed)"') encoded = '(encryption failed)' CACHED['ircbot'].privmsg(recipient, encoded)
def vote(request, poll_id): if not request.user.is_authenticated(): return HttpResponseRedirect("/") else: logged_in = True error = "" success = "" try: poll = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise Http404 username = request.user.username if ( (not poll.is_allowed_voter(username)) or poll.has_voted(username) or (poll.starts > datetime.datetime.now()) or (poll.ends < datetime.datetime.now()) ): return HttpResponseRedirect("/mypolls") poll_choices = Choice.objects.filter(poll=poll).order_by("id") choice_type = "radio" if poll.max_choices > 1: choice_type = "checkbox" vote_tag = "" vote_receipt_encrypted = "" if request.POST: form = Form(request.POST) if form.is_valid(): choices = request.POST.getlist("choices") # Check that the submitted choices exist and belong to the poll for choice in choices: try: c = Choice.objects.get(pk=choice, poll=poll) except Choice.DoesNotExist: error = "The submitted choices are not valid choices of the poll" # Check that the submitted choices are between min and max number of choices allowed for the poll if len(choices) > poll.max_choices: error = "You cannot vote for more than " + str(poll.max_choices) + " choices" if len(choices) < poll.min_choices: error = "You must vote for at least " + str(poll.min_choices) + " choices" if poll.max_choices == 1: # a better error message for single choice polls error = "You must select a choice" if list_has_duplicates(choices): error = "Each choice can be selected only once" if not error: # Construct a unique, random string to use as a vote tag while not vote_tag: vote_tag = "".join(random.choice(string.ascii_uppercase + string.digits) for x in range(35)) try: v = Vote.objects.get(tag=vote_tag) vote_tag = "" except Vote.DoesNotExist: # our random string is unique so we can use it as a vote tag # Encrypt the vote tag with user's public pgp key and sign it with the key of the system authority gpg = GPG(gpgbinary=settings.GNUPGBINARY, gnupghome=settings.GNUPGHOME) vote_receipt = """GPGVote: Vote Receipt --------------------- You are voter: %s You voted for Poll: \'%s\' Created by: %s Your Vote Tag is: %s You made the following choices:""" % ( request.user.pgpkey.name + " <" + request.user.username + ">", poll.question, poll.creator.pgpkey.name + " <" + poll.creator.username + ">", vote_tag, ) for choice in choices: choice = Choice.objects.get(pk=choice, poll=poll) vote_receipt = vote_receipt + "\n * %s" % choice.choice vote_receipt_encrypted = gpg.encrypt( vote_receipt, request.user.pgpkey.fingerprint, always_trust=True, sign=settings.SYSTEM_KEY_FINGERPRINT, passphrase=settings.SYSTEM_KEY_PASSWD, ) # Create the actual vote records in database for choice in choices: vote = Vote(choice=Choice.objects.get(id=choice), tag=vote_tag) vote.save() poll.add_voter(voter=username, To="who_voted") poll.save() success = "You have successfully voted for the poll" return render_to_response( "vote.html", { "user": username, "poll": poll, "choices": poll_choices, "choice_type": choice_type, "error": error, "success": success, "vote_receipt": vote_receipt_encrypted, "logged_in": logged_in, }, context_instance=RequestContext(request), )
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))
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)
gpg = GPG(gnupghome='.python-gnupg') gpg.encoding = 'utf-8' # These commands needed to be run once to generate and save the key #input_data = gpg.gen_key_input(key_type="RSA", key_length=2**KEY_EXP) #gpg_key = gpg.gen_key(input_data) # BEGIN BLOCK CIPHER OPERATIONS set_run = ['block'] setup = """\ from __main__ import gpg, message, enctext """ # Create cipher, create cipher text for decryption, time operations, update # result with each new operation algo_run = ['3DES'] enctext = gpg.encrypt(message, None, symmetric='3DES', passphrase=PASSPHRASE, armor=False) enc_run = ['encrypt'] enc_trial = Timer( "gpg.encrypt(message, None, symmetric='3DES', passphrase=PASSPHRASE, armor=False)", setup) enc_run.append(enc_trial.repeat(RUN_COUNT, 1)) algo_run.append(enc_run) dec_run = ['decrypt'] dec_trial = Timer( "gpg.decrypt(enctext.data, passphrase=PASSPHRASE)", setup) dec_run.append(dec_trial.repeat(RUN_COUNT, 1)) algo_run.append(dec_run) set_run.append(algo_run) # Create cipher, create cipher text for decryption, time operations, update
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 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 CryptoTxt: """Crypto operation provider for plaintext. We use GnuPG for now. Support for X.509 and other options might appear in the future. """ def __init__(self, gpg_binary, gpg_home): """Initialize the GnuPG instance.""" self.gpg_binary = gpg_binary self.gpg_home = gpg_home if not GPG: raise TracError(_("Unable to load the python-gnupg module. " "Please check and correct your installation.")) try: self.gpg = GPG(gpgbinary=self.gpg_binary, gnupghome=self.gpg_home) except ValueError: raise TracError(_("Missing the crypto binary. Please check and " "set full path with option 'gpg_binary'.")) else: # get list of available public keys once for later use self.pub_keys = self.gpg.list_keys() def sign(self, content, private_key=None): private_key = self._get_private_key(private_key) cipher = self.gpg.sign(content, keyid=private_key, passphrase='') return str(cipher) def encrypt(self, content, pubkeys): # always_trust needed for making it work with just any pubkey cipher = self.gpg.encrypt(content, pubkeys, always_trust=True) return str(cipher) def sign_encrypt(self, content, pubkeys, private_key=None): private_key = self._get_private_key(private_key) # always_trust needed for making it work with just any pubkey cipher = self.gpg.encrypt(content, pubkeys, always_trust=True, sign=private_key, passphrase='') return str(cipher) def get_pubkey_ids(self, addr): """Find public key with UID matching address to encrypt to.""" pubkey_ids = [] if self.pub_keys and 'uids' in self.pub_keys[-1] and \ 'fingerprint' in self.pub_keys[-1]: # compile pattern before use for better performance rcpt_re = re.compile(addr) for k in self.pub_keys: for uid in k['uids']: match = rcpt_re.search(uid) if match is not None: # check for key expiration if k['expires'] == '': pubkey_ids.append(k['fingerprint'][-16:]) elif (time.time() + 60) < float(k['expires']): pubkey_ids.append(k['fingerprint'][-16:]) break return pubkey_ids def _get_private_key(self, privkey=None): """Find private (secret) key to sign with.""" # read private keys from keyring privkeys = self.gpg.list_keys(True) # True => private keys if privkeys > 0 and 'fingerprint' in privkeys[-1]: fingerprints = [] for k in privkeys: fingerprints.append(k['fingerprint']) else: # no private key in keyring return None if privkey: # check for existence of private key received as argument # DEVEL: check for expiration as well if 7 < len(privkey) <= 40: for fp in fingerprints: if fp.endswith(privkey): # work with last 16 significant chars internally, # even if only 8 are required in trac.ini privkey = fp[-16:] break # no fingerprint matching key ID else: privkey = None else: # reset invalid key ID privkey = None else: # select (last) private key from keyring privkey = fingerprints[-1][-16:] return privkey
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 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 CryptoTxt: """Crypto operation provider for plaintext. We use GnuPG for now. Support for X.509 and other options might appear in the future. """ def __init__(self, gpg_binary, gpg_home): """Initialize the GnuPG instance.""" self.gpg_binary = gpg_binary self.gpg_home = gpg_home if not GPG: raise TracError( _("Unable to load the python-gnupg module. " "Please check and correct your installation.")) try: self.gpg = GPG(gpgbinary=self.gpg_binary, gnupghome=self.gpg_home) except ValueError: raise TracError( _("Missing the crypto binary. Please check and " "set full path with option 'gpg_binary'.")) else: # get list of available public keys once for later use self.pub_keys = self.gpg.list_keys() def sign(self, content, private_key=None): private_key = self._get_private_key(private_key) cipher = self.gpg.sign(content, keyid=private_key, passphrase='') return str(cipher) def encrypt(self, content, pubkeys): # always_trust needed for making it work with just any pubkey cipher = self.gpg.encrypt(content, pubkeys, always_trust=True) return str(cipher) def sign_encrypt(self, content, pubkeys, private_key=None): private_key = self._get_private_key(private_key) # always_trust needed for making it work with just any pubkey cipher = self.gpg.encrypt(content, pubkeys, always_trust=True, sign=private_key, passphrase='') return str(cipher) def get_pubkey_ids(self, addr): """Find public key with UID matching address to encrypt to.""" pubkey_ids = [] if self.pub_keys and 'uids' in self.pub_keys[-1] and \ 'fingerprint' in self.pub_keys[-1]: # compile pattern before use for better performance rcpt_re = re.compile(addr) for k in self.pub_keys: for uid in k['uids']: match = rcpt_re.search(uid) if match is not None: # check for key expiration if k['expires'] == '': pubkey_ids.append(k['fingerprint'][-16:]) elif (time.time() + 60) < float(k['expires']): pubkey_ids.append(k['fingerprint'][-16:]) break return pubkey_ids def _get_private_key(self, privkey=None): """Find private (secret) key to sign with.""" # read private keys from keyring privkeys = self.gpg.list_keys(True) # True => private keys if privkeys > 0 and 'fingerprint' in privkeys[-1]: fingerprints = [] for k in privkeys: fingerprints.append(k['fingerprint']) else: # no private key in keyring return None if privkey: # check for existence of private key received as argument # DEVEL: check for expiration as well if 7 < len(privkey) <= 40: for fp in fingerprints: if fp.endswith(privkey): # work with last 16 significant chars internally, # even if only 8 are required in trac.ini privkey = fp[-16:] break # no fingerprint matching key ID else: privkey = None else: # reset invalid key ID privkey = None else: # select (last) private key from keyring privkey = fingerprints[-1][-16:] return privkey
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))
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 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 GpgSandbox: """ The GPG sandbox wraps a :class:`gnupg.GPG` instance that uses a temporary directory as its home directory. This allows to import keys without messing with the user's system. It automatically imports files named `*.key` placed in `keys_dir` (`data/keys`) by default. The keys can then be referenced by their filename minus the `.key` extension, for example `john.doe.key` can then be used with `gpg.get_key('john.doe'). """ def __init__(self, tmpdir: str, keys_dir: str = 'data/keys') -> None: # GPG needs the homedir to have limited permissions os.chmod(tmpdir, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) self.homedir = tmpdir self.gpg = GPG(gnupghome=tmpdir) self.keys = self.import_keys(keys_dir) def get_key_files(self, keys_dir: str) -> Iterable[str]: """ Return the list of key files in the keys directory. """ return glob.glob( os.path.join(os.path.dirname(__file__), '..', keys_dir, '*.key')) def import_key(self, key: str) -> str: """ Import the given armored key and return its fingerprint. """ import_result = self.gpg.import_keys(key) return import_result.fingerprints[0] def import_keys(self, keys_dir: str) -> Dict[str, Tuple[str, str]]: """ Iterate over the `.key` files in `keys_dir` and import then into GPG. """ keys = {} for key_path in self.get_key_files(keys_dir): username = os.path.basename(key_path)[:-len('.key')] with open(key_path) as key_file: key = key_file.read() keys[username] = (self.import_key(key), key) return keys def encrypt(self, data: str, username: str) -> str: """ Return `data` encrypted for `username`, which should match a key in the keys directory. """ return str( self.gpg.encrypt(data, self.keys[username][0], always_trust=True)) def decrypt(self, data: str) -> str: """ Return `data` decrypted. A corresponding private key must be available so this data can be decrypted. """ return str(self.gpg.decrypt(data, always_trust=True)) def get_fingerprint(self, username: str) -> str: """ Return the key fingerprint of the given username. """ return self.keys[username][0] def get_key(self, username: str) -> str: """ Return the armored key of the given username. """ return self.keys[username][1]
gpg = GPG(binary='/usr/bin/gpg2', homedir='~/.gnupg', keyring='pubring.gpg', secring='secring.gpg') stored_keys = gpg.list_keys() message = "This is a test message to be encripted." options_enc = { 'passphrase': passphrase, 'armor': True, 'default_key': gpg_test_fingerprint } encrypted_msg = gpg.encrypt(message, gpg_test_fingerprint, **options_enc) print(encrypted_msg) options_dec = { 'passphrase': passphrase } decrypted_msg = gpg.decrypt(str(encrypted_msg), **options_dec) assert message == str(decrypted_msg) print("This is the original message:", decrypted_msg) ''' "Valid" will return a boolean saying whether the decrypted message's signature is valid.''' assert decrypted_msg.valid
getCoreLogger().exception("GPG not working: "+str(e)) sys.exit(1) db_file = os.path.join(get_settings().get_main_config_dir(),"lunchinator.sq3") tries = 10 public_key = "0x17F57DC2" cnx = sqlite3.connect(db_file) cursor = cnx.cursor() p,e,c,ce,ec,s,sc,es,esc,cnt = (0,)*10 cursor.execute("select mtype || \" \" || message from statistics_messages where mtype='HELO_INFO' order by rtime desc limit %d"%tries) tries = 0 for (rec,) in cursor: plain_text = rec.encode("utf8") enc_data = str(gpg.encrypt(plain_text, public_key, always_trust=True)) enc_data_comp = zlib.compress(enc_data) comp_data = zlib.compress(plain_text) comp_data_enc = str(gpg.encrypt(comp_data, public_key, always_trust=True)) sign_data = str(gpg.sign(plain_text)) sign_data_comp = zlib.compress(sign_data) sign_enc_data = str(gpg.encrypt(plain_text, public_key, sign=public_key, always_trust=True)) sign_enc_data_comp = zlib.compress(sign_enc_data) p+=len(plain_text) e+=len(enc_data) c+=len(comp_data) ce+=len(comp_data_enc)
class Axolotl: def __init__(self, name, dbname='axolotl.db', dbpassphrase='', user_pathstring='~'): self.ratchetKey = None self.ratchetPKey = None self.name = name self.db = None self.mode = None self.staged_HK_mk = None self.state = None self.handshakeKey = None self.handshakePKey = None self.storeTime = None user_path = os.path.expanduser(user_pathstring) keyring = [user_path + '/.gnupg/pubring.gpg'] secret_keyring = [user_path + '/.gnupg/secring.gpg'] self.dbname = user_path + '/tmp/pyaxo_db/' + dbname self.gpg = GPG(gnupghome=user_path + '/.axolotl', gpgbinary='gpg', keyring=keyring, secret_keyring=secret_keyring, options=['--throw-keyids', '--personal-digest-preferences=sha256', '--s2k-digest-algo=sha256']) self.gpg.encoding = 'utf-8' if dbpassphrase != '' or dbpassphrase is None: self.dbpassphrase = dbpassphrase else: self.dbpassphrase = getpass( 'Database passphrase for ' + self.name + ': ').strip() self.db_init() def db_init(self): try: self.db = self.open_db() except sqlite3.OperationalError: raise (Axolotl_exception('Bad sql! Password problem - \ cannot create the database.')) self.mode = None self.staged_HK_mk = {} self.state = {} self.state['DHIs_priv'], self.state['DHIs'] = self.genKey() self.state['DHRs_priv'], self.state['DHRs'] = self.genKey() self.handshakeKey, self.handshakePKey = self.genKey() # minimum time (seconds) to store missed ephemeral message keys self.storeTime = 2 * 86400 with self.db: cur = self.db.cursor() cur.execute(""" CREATE TABLE IF NOT EXISTS skipped_mk (my_identity, to_identity, HKr TEXT, mk TEXT, timestamp INTEGER )""") cur.execute(""" CREATE UNIQUE INDEX IF NOT EXISTS message_keys ON skipped_mk (mk)""") cur.execute(""" CREATE TABLE IF NOT EXISTS conversations (my_identity TEXT, other_identity TEXT, RK TEXT, HKs TEXT, HKr TEXT, NHKs TEXT, NHKr TEXT, CKs TEXT, CKr TEXT, DHIs_priv TEXT, DHIs TEXT, DHIr TEXT, DHRs_priv TEXT, DHRs TEXT, DHRr TEXT, CONVid TEXT, Ns INTEGER, Nr INTEGER, PNs INTEGER, ratchet_flag INTEGER, mode INTEGER)""") cur.execute(""" CREATE UNIQUE INDEX IF NOT EXISTS conversation_route ON conversations (my_identity, other_identity)""") self.commit_skipped_mk() def triple_dh(self, a, a0, B, B0): if self.mode is None: raise (Axolotl_exception('Mode must be set')) if self.mode: return sha256( self.gen_dh(a, B0) + self.gen_dh(a0, B) + self.gen_dh(a0, B0)).digest() else: return sha256( self.gen_dh(a0, B) + self.gen_dh(a, B0) + self.gen_dh(a0, B0)).digest() def initState(self, other_name, other_identityKey, other_handshakeKey, other_ratchetKey, verify=True): if verify: print('Confirm ' + other_name + ' has identity key fingerprint:\n') fingerprint = sha224(other_identityKey).hexdigest().upper() fprint = '' for i in range(0, len(fingerprint), 4): fprint += fingerprint[i:i + 2] + ':' print(fprint[:-1] + '\n') print('Be sure to verify this fingerprint with ' + other_name + ' by some out-of-band method!') print('Otherwise, you may be subject to a \ Man-in-the-middle attack!\n') ans = raw_input('Confirm? y/N: ').strip() if ans != 'y': raise (Axolotl_exception('Key fingerprint \ not confirmed - exception')) if self.state['DHIs'] < other_identityKey: self.mode = True else: self.mode = False mkey = self.triple_dh(self.state['DHIs_priv'], self.handshakeKey, other_identityKey, other_handshakeKey) self.createState(other_name, mkey, mode=self.mode, other_identityKey=other_identityKey, other_ratchetKey=other_ratchetKey) def createState(self, other_name, mkey, mode=None, other_identityKey=None, other_ratchetKey=None): self.mode = mode if self.mode is None: # mode not selected raise (Axolotl_exception('Mode must be set')) if self.mode: # alice mode RK = pbkdf2(mkey, b'\x00', 10, prf='hmac-sha256') HKs = None HKr = pbkdf2(mkey, b'\x02', 10, prf='hmac-sha256') NHKs = pbkdf2(mkey, b'\x03', 10, prf='hmac-sha256') NHKr = pbkdf2(mkey, b'\x04', 10, prf='hmac-sha256') CKs = None CKr = pbkdf2(mkey, b'\x06', 10, prf='hmac-sha256') DHRs_priv = None DHRs = None DHRr = other_ratchetKey CONVid = pbkdf2(mkey, b'\x07', 10, prf='hmac-sha256') Ns = 0 Nr = 0 PNs = 0 ratchet_flag = True else: # bob mode RK = pbkdf2(mkey, b'\x00', 10, prf='hmac-sha256') HKs = pbkdf2(mkey, b'\x02', 10, prf='hmac-sha256') HKr = None NHKs = pbkdf2(mkey, b'\x04', 10, prf='hmac-sha256') NHKr = pbkdf2(mkey, b'\x03', 10, prf='hmac-sha256') CKs = pbkdf2(mkey, b'\x06', 10, prf='hmac-sha256') CKr = None DHRs_priv = self.state['DHRs_priv'] DHRs = self.state['DHRs'] DHRr = None CONVid = pbkdf2(mkey, b'\x07', 10, prf='hmac-sha256') Ns = 0 Nr = 0 PNs = 0 ratchet_flag = False DHIr = other_identityKey self.state = \ {'name': self.name, 'other_name': other_name, 'RK': RK, 'HKs': HKs, 'HKr': HKr, 'NHKs': NHKs, 'NHKr': NHKr, 'CKs': CKs, 'CKr': CKr, 'DHIs_priv': self.state['DHIs_priv'], 'DHIs': self.state['DHIs'], 'DHIr': DHIr, 'DHRs_priv': DHRs_priv, 'DHRs': DHRs, 'DHRr': DHRr, 'CONVid': CONVid, 'Ns': Ns, 'Nr': Nr, 'PNs': PNs, 'ratchet_flag': ratchet_flag, } self.ratchetKey = False self.ratchetPKey = False def encrypt(self, plaintext): if self.state['ratchet_flag']: self.state['DHRs_priv'], self.state['DHRs'] = self.genKey() self.state['HKs'] = self.state['NHKs'] self.state['RK'] = sha256(self.state['RK'] + self.gen_dh( self.state['DHRs_priv'], self.state['DHRr'])).digest() if self.mode: self.state['NHKs'] = pbkdf2(self.state['RK'], b'\x03', 10, prf='hmac-sha256') self.state['CKs'] = pbkdf2(self.state['RK'], b'\x05', 10, prf='hmac-sha256') else: self.state['NHKs'] = pbkdf2(self.state['RK'], b'\x04', 10, prf='hmac-sha256') self.state['CKs'] = pbkdf2(self.state['RK'], b'\x06', 10, prf='hmac-sha256') self.state['PNs'] = self.state['Ns'] self.state['Ns'] = 0 self.state['ratchet_flag'] = False mk = sha256(self.state['CKs'] + '0').digest() msg1 = self.enc(self.state['HKs'], str(self.state['Ns']).zfill(3) + str(self.state['PNs']).zfill(3) + self.state['DHRs']) msg2 = self.enc(mk, plaintext) pad_length = 106 - len(msg1) pad = os.urandom(pad_length - 1) + chr(pad_length) msg = msg1 + pad + msg2 self.state['Ns'] += 1 self.state['CKs'] = sha256(self.state['CKs'] + '1').digest() return msg def commit_skipped_mk(self): timestamp = int(time()) with self.db: cur = self.db.cursor() for mk, HKr in self.staged_HK_mk.iteritems(): cur.execute("""REPLACE INTO skipped_mk (my_identity, to_identity, HKr, mk, timestamp ) VALUES (?, ?, ?, ?, ?)""", self.state['name'], self.state['other_name'], b2a_base64(HKr).strip(), b2a_base64(mk).strip(), timestamp) rowtime = timestamp - self.storeTime cur.execute('DELETE FROM skipped_mk WHERE timestamp < ?', (rowtime,)) def trySkippedMK(self, msg, pad_length, name, other_name): with self.db: cur = self.db.cursor() cur.execute('SELECT * FROM skipped_mk') rows = cur.fetchall() for row in rows: if name == row[0] and other_name == row[1]: msg1 = msg[:106 - pad_length] msg2 = msg[106:] header = self.dec(a2b_base64(row[2]), msg1) body = self.dec(a2b_base64(row[3]), msg2) if header != '' and body != '': cur.execute('DELETE FROM skipped_mk WHERE mk = ?', (row[3],)) return body return False def stageSkippedMK(self, HKr, Nr, Np, CKr): CKp = CKr for i in range(Np - Nr): mk = sha256(CKp + '0').digest() CKp = sha256(CKp + '1').digest() self.staged_HK_mk[mk] = HKr mk = sha256(CKp + '0').digest() CKp = sha256(CKp + '1').digest() return CKp, mk def decrypt(self, msg): pad = msg[105:106] pad_length = ord(pad) msg1 = msg[:106 - pad_length] body = self.trySkippedMK(msg, pad_length, self.state['name'], self.state['other_name']) if body and body != '': return body header = None if self.state['HKr']: header = self.dec(self.state['HKr'], msg1) if header and header != '': Np = int(header[:3]) CKp, mk = self.stageSkippedMK(self.state['HKr'], self.state['Nr'], Np, self.state['CKr']) body = self.dec(mk, msg[106:]) if not body or body == '': raise (Axolotl_exception('Undecipherable message')) else: header = self.dec(self.state['NHKr'], msg1) if self.state['ratchet_flag'] or not header or header == '': raise (Axolotl_exception('Undecipherable message')) Np = int(header[:3]) PNp = int(header[3:6]) DHRp = header[6:] if self.state['CKr']: self.stageSkippedMK(self.state['HKr'], self.state['Nr'], PNp, self.state['CKr']) HKp = self.state['NHKr'] RKp = sha256( self.state['RK'] + self.gen_dh(self.state['DHRs_priv'], DHRp)).digest() if self.mode: NHKp = pbkdf2(RKp, b'\x04', 10, prf='hmac-sha256') CKp = pbkdf2(RKp, b'\x06', 10, prf='hmac-sha256') else: NHKp = pbkdf2(RKp, b'\x03', 10, prf='hmac-sha256') CKp = pbkdf2(RKp, b'\x05', 10, prf='hmac-sha256') CKp, mk = self.stageSkippedMK(HKp, 0, Np, CKp) body = self.dec(mk, msg[106:]) if not body or body == '': raise (Axolotl_exception('Undecipherable message')) self.state['RK'] = RKp self.state['HKr'] = HKp self.state['NHKr'] = NHKp self.state['DHRr'] = DHRp self.state['DHRs_priv'] = None self.state['DHRs'] = None self.state['ratchet_flag'] = True self.commit_skipped_mk() self.state['Nr'] = Np + 1 self.state['CKr'] = CKp return body def encrypt_file(self, filename): with open(filename, 'r') as f: plaintext = f.read() ciphertext = b2a_base64(self.encrypt(plaintext)) with open(filename + '.asc', 'w') as f: lines = [ciphertext[i:i + 64] for i in xrange(0, len(ciphertext), 64)] for line in lines: f.write(line + '\n') def decrypt_file(self, filename): with open(filename, 'r') as f: ciphertext = a2b_base64(f.read()) plaintext = self.decrypt(ciphertext) print(plaintext) def encrypt_pipe(self): plaintext = sys.stdin.read() ciphertext = b2a_base64(self.encrypt(plaintext)) sys.stdout.write(ciphertext) sys.stdout.flush() def decrypt_pipe(self): ciphertext = a2b_base64(sys.stdin.read()) plaintext = self.decrypt(ciphertext) sys.stdout.write(plaintext) sys.stdout.flush() def printKeys(self): print('Your Identity key is:\n' + b2a_base64( self.state['DHIs'])) fingerprint = sha224(self.state['DHIs']).hexdigest().upper() fprint = '' for i in range(0, len(fingerprint), 4): fprint += fingerprint[i:i + 2] + ':' print('Your identity key fingerprint is: ') print(fprint[:-1] + '\n') print('Your Ratchet key is:\n' + b2a_base64( self.state['DHRs'])) if self.handshakeKey: print('Your Handshake key is:\n' + b2a_base64( self.handshakePKey)) else: print('Your Handshake key is not available') def to_json(self): _j = {'name': self.name, 'identity_key': b2a_base64(self.state('DHIs')), 'fingerprint': sha224(self.state['DHIs']).hexdigest().upper(), 'ratchet_key': b2a_base64(self.state['DHRs'])} return json.dumps(_j) def init_from_json(self, _jsn): _k = json.loads(_jsn) self.initState(_k['name'], a2b_base64(_k['identity_key']), a2b_base64(_k['fingerprint']), a2b_base64(_k['ratchet_key'])) self.saveState() def saveState(self): ktup = ('HKs', 'HKr', 'CKs', 'CKR', 'DHIr', 'DHRs_priv', 'DHRs') v = {k: b2a_base64(self.state[k]).strip for k in ktup} ratchet_flag = 1 if self.state['ratchet_flag'] else 0 mode = 1 if self.mode else 0 with self.db: cur = self.db.cursor() cur.execute("""\ REPLACE INTO conversations ( my_identity, other_identity, RK,HKS, HKr, NHKs, NHKr, CKs, CKr, DHIs_priv, DHIs, DHIr, DHRs_priv, DHRs, DHRr, CONVid, Ns, Nr, PNs, ratchet_flag, mode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", (self.state['name'], self.state['other_name'], b2a_base64(self.state['RK']).strip(), v['HKs'], v['HKr'], b2a_base64(self.state['NHKs']).strip(), b2a_base64(self.state['NHKr']).strip(), v['CKs'], v['CKr'], b2a_base64(self.state['DHIs_priv']).strip(), b2a_base64(self.state['DHIs']).strip(), v['DHIr'], v['DHRs_priv'], v['DHRs'], v['DHRr'], b2a_base64(self.state['CONVid']).strip(), self.state['Ns'], self.state['Nr'], self.state['PNs'], ratchet_flag, mode )) self.write_db() def loadState(self, name, other_name): self.db = self.open_db() with self.db: cur = self.db.cursor() try: cur.execute('SELECT * FROM conversations') except sqlite3.OperationalError: raise (Axolotl_exception('Bad sql! Password problem - \ cannot loadState()')) rows = cur.fetchall() for row in rows: if row[0] == name and row[1] == other_name: self.state = {'name': row[0], 'other_name': row[1], 'RK': a2b_base64(row[2]), 'NHKs': a2b_base64(row[5]), 'NHKr': a2b_base64(row[6]), 'DHIs_priv': a2b_base64(row[9]), 'DHIs': a2b_base64(row[10]), 'CONVid': a2b_base64(row[15]), 'Ns': row[16], 'Nr': row[17], 'PNs': row[18]} self.name = self.state['name'] def do_bin(loc): if row[loc] == '0': return None else: return a2b_base64(row[loc]) self.state['HKs'] = do_bin(3) self.state['HKr'] = do_bin(4) self.state['CKs'] = do_bin(7) self.state['CKr'] = do_bin(8) self.state['DHIr'] = do_bin(11) self.state['DHRs_priv'] = do_bin(12) self.state['DHRs'] = do_bin(13) self.state['DHRr'] = do_bin(14) ratchet_flag = row[19] if ratchet_flag == 1: self.state['ratchet_flag'] = True else: self.state['ratchet_flag'] = False mode = row[20] self.mode = True if mode == 1 else False return # exit at first match return False # if no matches def open_db(self): db = sqlite3.connect(':memory:') try: with open(self.dbname, 'rb') as f: if self.dbpassphrase is not None: sql = \ self.gpg.decrypt_file(f, passphrase=self.dbpassphrase) if sql is not None and sql != '': db.cursor().executescript(sql.data) return db else: raise (Axolotl_exception('Bad passphrase!')) else: sql = f.read() db.cursor().executescript(sql) return db except IOError: return db def write_db(self): sql = '' for item in self.db.iterdump(): sql = sql + item + '\n' if self.dbpassphrase is not None: crypt_sql = self.gpg.encrypt(sql, recipients=None, symmetric='AES256', armor=False, always_trust=True, passphrase=self.dbpassphrase) with open(self.dbname, 'wb') as f: f.write(crypt_sql.data) else: with open(self.dbname, 'w') as f: f.write(sql) def print_state(self): print('\nWarning: saving this data to disk is insecure!\n') for key in sorted(self.state): if 'priv' in key: pass else: if self.state[key] is None: print(key + ': None') elif type(self.state[key]) is bool: if self.state[key]: print(key + ': True') else: print(key + ': False') elif type(self.state[key]) is str: try: self.state[key].decode('ascii') print(key + ': ' + self.state[key]) except UnicodeDecodeError: print(key + ': ' + b2a_base64( self.state[key]).strip()) else: print(key + ': ' + str(self.state[key])) if self.mode: print('Mode: Alice') else: print('Mode: Bob') @staticmethod def genKey(): key = keys.Private() privkey = key.private pubkey = key.get_public().serialize() return privkey, pubkey @staticmethod def gen_dh(a, B): key = keys.Private(secret=a) return key.get_shared_key(keys.Public(B)) def dec(self, key, encrypted): key = hexlify(key) msg = self.gpg.decrypt(GPG_HEADER + encrypted, passphrase=key, always_trust=True) return msg.data def enc(self, key, plaintext): key = hexlify(key) msg = self.gpg.encrypt(plaintext, recipients=None, symmetric=GPG_CIPHER, armor=False, always_trust=True, passphrase=key) return msg.data[6:]
def encrypt(data: str, fingerprint: str, gpg: GPG) -> str: """ Encrypt data for the given `fingerprint`. The key must be imported in the GPG keys directory first. """ return str(gpg.encrypt(data, fingerprint, always_trust=True))
args = parser.parse_args() gpg_home, pass_loc = get_env_vars() gpg = GPG(gnupghome=gpg_home) with open(pass_loc, mode='rb') as f: decoded = gpg.decrypt_file(f, passphrase=getpass()) if decoded.data == b'': print("Incorrect Passphrase") exit() passes = loads(clean_gpg_json(decoded.data)) if args.list: for key in passes.keys(): print(key) if args.key is not None: if args.password: print_pass(passes, args.key) if args.user: print_user(passes, args.key) if args.set or args.remove: keys = gpg.list_keys() for index, key in enumerate(keys): print(index, key['uids']) fp = keys[int(input('Pick gpg key: '))]['fingerprint'] key = input('Specify key: ') if args.set: passes[key] = getpass() else: del passes[key] with open(pass_loc, 'wb') as f: f.write(gpg.encrypt(dumps(passes), fp).data)
def vote(request, poll_id): if not request.user.is_authenticated(): return HttpResponseRedirect('/') else: logged_in = True error = '' success = '' try: poll = Poll.objects.get(pk=poll_id) except Poll.DoesNotExist: raise Http404 username = request.user.username if (not poll.is_allowed_voter(username)) \ or poll.has_voted(username) \ or (poll.starts > datetime.datetime.now()) \ or (poll.ends < datetime.datetime.now()): return HttpResponseRedirect('/mypolls') poll_choices = Choice.objects.filter(poll=poll).order_by('id') choice_type = "radio" if poll.max_choices > 1: choice_type = "checkbox" vote_tag = '' vote_receipt_encrypted = '' if request.POST: form = Form(request.POST) if form.is_valid(): choices = request.POST.getlist('choices') # Check that the submitted choices exist and belong to the poll for choice in choices: try: c = Choice.objects.get(pk=choice, poll=poll) except Choice.DoesNotExist: error = "The submitted choices are not valid choices of the poll" # Check that the submitted choices are between min and max number of choices allowed for the poll if len(choices) > poll.max_choices: error = 'You cannot vote for more than ' + str( poll.max_choices) + ' choices' if len(choices) < poll.min_choices: error = 'You must vote for at least ' + str( poll.min_choices) + ' choices' if poll.max_choices == 1: # a better error message for single choice polls error = 'You must select a choice' if list_has_duplicates(choices): error = 'Each choice can be selected only once' if not error: # Construct a unique, random string to use as a vote tag while not vote_tag: vote_tag = ''.join( random.choice(string.ascii_uppercase + string.digits) for x in range(35)) try: v = Vote.objects.get(tag=vote_tag) vote_tag = '' except Vote.DoesNotExist: # our random string is unique so we can use it as a vote tag # Encrypt the vote tag with user's public pgp key and sign it with the key of the system authority gpg = GPG(gpgbinary=settings.GNUPGBINARY, gnupghome=settings.GNUPGHOME) vote_receipt = """GPGVote: Vote Receipt --------------------- You are voter: %s You voted for Poll: \'%s\' Created by: %s Your Vote Tag is: %s You made the following choices:""" % (request.user.pgpkey.name + ' <' + request.user.username + '>', poll.question, \ poll.creator.pgpkey.name + ' <' + poll.creator.username + '>', vote_tag) for choice in choices: choice = Choice.objects.get(pk=choice, poll=poll) vote_receipt = vote_receipt + '\n * %s' % choice.choice vote_receipt_encrypted = gpg.encrypt( vote_receipt, request.user.pgpkey.fingerprint, always_trust=True, sign=settings.SYSTEM_KEY_FINGERPRINT, passphrase=settings.SYSTEM_KEY_PASSWD) # Create the actual vote records in database for choice in choices: vote = Vote(choice=Choice.objects.get(id=choice), tag=vote_tag) vote.save() poll.add_voter(voter=username, To='who_voted') poll.save() success = 'You have successfully voted for the poll' return render_to_response('vote.html', { 'user': username, 'poll': poll, 'choices': poll_choices, 'choice_type': choice_type, 'error': error, 'success': success, 'vote_receipt': vote_receipt_encrypted, 'logged_in': logged_in }, context_instance=RequestContext(request))