def verify(self, gpg_uid): if not has_pyme: raise Exception('pyme is required, please install: pip install --pre pyme3. You will also need libgpg-error-dev and libgpgme11-dev.') to_return = {} signed_data = self._serialize() with gpg.Context() as c: keys = list(c.keylist(gpg_uid)) try: c.verify(signed_data, signature=base64.b64decode(self.sig), verify=keys[:1]) to_return[self.uuid] = True except: to_return[self.uuid] = False for a in self.attributes: to_return.update(a.verify(gpg_uid)) to_verify_global = self._serialize_sigs() with gpg.Context() as c: keys = list(c.keylist(gpg_uid)) try: c.verify(to_verify_global, signature=base64.b64decode(self.global_sig), verify=keys[:1]) to_return['global'] = True except: to_return['global'] = False return to_return
def verify(signature_file, filename): c = gpg.Context() _, result = c.verify(open(filename), open(signature_file)) for signature in result.signatures: message = ''' Good signature from "{user}" with key {fingerprint} made at {time} '''.format(user=c.get_key(signature.fpr).uids[0].uid, fingerprint=signature.fpr, time=time.ctime(signature.timestamp)) print(textwrap.dedent(message))
def sign(self, gpg_uid, passphrase=None): # pragma: no cover # Not used if not has_pyme: raise PyMISPError( 'pyme is required, please install: pip install --pre pyme3. You will also need libgpg-error-dev and libgpgme11-dev.' ) to_sign = self._serialize() with gpg.Context() as c: keys = list(c.keylist(gpg_uid)) c.signers = keys[:1] if passphrase: c.set_passphrase_cb(lambda *args: passphrase) signed, _ = c.sign(to_sign, mode=mode.DETACH) self.sig = base64.b64encode(signed).decode()
def __init__(self, key_id, gpg_home='~/.gnupg', sig_ext='.asc', gpg_armor=True): os.environ['GNUPGHOME'] = os.path.abspath(os.path.expanduser(gpg_home)) self.sig_ext = sig_ext self.gpg = gpg.Context() # has to be an iterable self.gpg.signers = [] self.key = self.gpg.get_key(key_id, True) if self.key.can_sign: self.gpg.signers.append(self.key) self.gpg.armor = True
def tag_create( repo, tag, author=None, message=None, annotated=False, objectish="HEAD", tag_time=None, tag_timezone=None, sign=False): """Creates a tag in git via dulwich calls: :param repo: Path to repository :param tag: tag string :param author: tag author (optional, if annotated is set) :param message: tag message (optional) :param annotated: whether to create an annotated tag :param objectish: object the tag should point at, defaults to HEAD :param tag_time: Optional time for annotated tag :param tag_timezone: Optional timezone for annotated tag :param sign: GPG Sign the tag """ with open_repo_closing(repo) as r: object = parse_object(r, objectish) if annotated: # Create the tag object tag_obj = Tag() if author is None: # TODO(jelmer): Don't use repo private method. author = r._get_user_identity(r.get_config_stack()) tag_obj.tagger = author tag_obj.message = message tag_obj.name = tag tag_obj.object = (type(object), object.id) if tag_time is None: tag_time = int(time.time()) tag_obj.tag_time = tag_time if tag_timezone is None: # TODO(jelmer) Use current user timezone rather than UTC tag_timezone = 0 elif isinstance(tag_timezone, str): tag_timezone = parse_timezone(tag_timezone) tag_obj.tag_timezone = tag_timezone if sign: import gpg with gpg.Context(armor=True) as c: tag_obj.signature, unused_result = c.sign( tag_obj.as_raw_string()) r.object_store.add_object(tag_obj) tag_id = tag_obj.id else: tag_id = object.id r.refs[_make_tag_ref(tag)] = tag_id
def initHome(self): if not self.home: h = os.environ.get('GNUPGHOME') if h: self.home = h if self.home: self.home = os.path.abspath(os.path.expanduser(self.home)) if not os.path.isdir(self.home): raise ValueError('GPG home does not exist') _logger.debug( 'Set GPG home to explicitly specified value {0}'.format( self.home)) self.gpg = gpg.Context(home_dir=self.home) return (None)
def interact(key, commands): c = gpg.Context() keys = list(c.keylist(key)) print_debug(keys, end="\n\n") if len(keys) != 1: if len(keys) == 0: error_msg = r"No key matching {key}" else: error_msg = r"More than 1 matching keys for {key}" fail(error_msg.format(key=key)) editor = KeyEditor(commands, 2) c.interact(keys[0], editor.edit_fnc) assert editor.done
def sign_and_verify(source, signed, sink): with gpg.Context() as c: c.op_sign(source, signed, gpg.constants.sig.mode.NORMAL) signed.seek(0, os.SEEK_SET) c.op_verify(signed, None, sink) result = c.op_verify_result() assert len(result.signatures) == 1, "Unexpected number of signatures" sig = result.signatures[0] assert sig.summary == (gpg.constants.sigsum.VALID | gpg.constants.sigsum.GREEN) assert gpg.errors.GPGMEError(sig.status).getcode() == gpg.errors.NO_ERROR sink.seek(0, os.SEEK_SET) assert sink.read() == b"Hallo Leute\n"
def delete(contacts, force): c = gpg.Context() for contact in contacts: keys = list(c.keylist(contact)) ans = "n" for key in keys: if not force: print_key(key.fpr, end="\n") try: ans = input("Delete this contact? (y/N)") except EOFError: exit(0) if ans.lower() == 'y' or force: c.op_delete(key, False)
def verify(self, gpg_uid): if not has_pyme: raise PyMISPError( 'pyme is required, please install: pip install --pre pyme3. You will also need libgpg-error-dev and libgpgme11-dev.' ) signed_data = self._serialize() with gpg.Context() as c: keys = list(c.keylist(gpg_uid)) try: c.verify(signed_data, signature=base64.b64decode(self.sig), verify=keys[:1]) return {self.uuid: True} except: return {self.uuid: False}
def __init__(self, filename=None, gpghome=None): """ Instantiate a credential manager """ if gpghome is None: gpghome = getenv('GNUPGHOME', str(Path.home().joinpath('.gnupg'))) if not Path(gpghome).exists(): raise FileNotFoundError(f"{gpghome}: No such file or directory") if not access(gpghome, R_OK | W_OK | X_OK): raise PermissionError(f"{gpghome}: Permission denied") self.__accounts = {} self.__filename = filename self.__encoder = json.JSONEncoder() self.__decoder = json.JSONDecoder() self.__gpg = gpg.Context(armor=True, home_dir=gpghome) self.load()
def print_signatures(verify_result): c = gpg.Context() for signature in verify_result.signatures: user = c.get_key(signature.fpr).uids[0].uid fpr = signature.fpr signed_time = time.ctime(signature.timestamp) message = ''' Good signature from "{user}" with key {fingerprint} made at {time} '''.format(user=user, fingerprint=fpr, time=signed_time) print(textwrap.dedent(message))
def setup(self, config): global legacy_gpg if legacy_gpg: protocol = gpgme.PROTOCOL_OpenPGP self._ctx = gpgme.Context() else: protocol = gpg.constants.PROTOCOL_OpenPGP self._ctx = gpg.Context() if config.has_option('gpg', 'executable'): executable = config.get('gpg', 'executable') else: executable = None # Default value gpg_home = config.get('gpg', 'home') self._ctx.set_engine_info(protocol, executable, gpg_home) self._ctx.armor = True
def get_all_keys(self): c = gpg.Context() for key in c.keylist(): user = key.uids[0] print("Keys for %s (%s):" % (user.name, user.email)) for subkey in key.subkeys: features = [] if subkey.can_authenticate: features.append('auth') if subkey.can_certify: features.append('cert') if subkey.can_encrypt: features.append('encrypt') if subkey.can_sign: features.append('sign') print(' %s %s' % (subkey.fpr, ','.join(features)))
def sign_doc(doc, key_id, passphrase_file): """ Create an OpenGPG signature for the doc. Parameters ---------- doc : bytes Message to clear-sign with OpenGPG key_id : str The key to use for signing passphrase_file : path Path to a file with the passphrase for the PGP key as the first line Returns ------- signature : bytes The ASCII armored signature of the document. Raises ------ SigningError If the document could not be signed for any reason """ try: import gpg from gpg.constants.sig import mode from gpg import constants except ImportError: raise SigningError('Could not import gpg') with gpg.Context(armor=True, pinentry_mode=constants.PINENTRY_MODE_LOOPBACK) as c: try: key = list(c.keylist(key_id))[0] except IndexError: raise SigningError(f'No key found in keyring with ID: {key_id}') c.signers = [key] c.set_passphrase_cb( lambda *args: open(passphrase_file, 'rb').readline()) try: signed_body, _ = c.sign(doc, mode=mode.DETACH) except gpg.errors.GPGMEError as e: raise SigningError(f'Internal GPGME error: {str(e)}') except FileNotFoundError: raise SigningError('No GPG password file found') return signed_body
def _encrypt(recipients, file_name, home=None): gpg_home = os.path.join(home, 'gpg') tmp_home = os.path.join(home, 'tmp') context = gpg.Context(armor=True, home_dir=gpg_home) recipient_keys = [] for recipient in recipients: recipient_keys.extend(context.keylist(pattern=recipient, secret=False)) with open(file_name, 'rb') as plain_text, \ tempfile.NamedTemporaryFile(dir=tmp_home, delete=False) as encrypted_file: result, _, _ = context.encrypt(plain_text.read(), recipients=recipient_keys, sign=False, always_trust=True) encrypted_file.write(result) os.unlink(file_name) return encrypted_file.name
def verify(second_try=False): with gpg.Context() as c: c.set_engine_info(gpg.constants.protocol.OpenPGP, home_dir=self.common.paths['gnupg_homedir']) sig = gpg.Data(file=self.common.paths['sig_file']) signed = gpg.Data(file=self.common.paths['tarball_file']) try: c.verify(signature=sig, signed_data=signed) except gpg.errors.BadSignatures as e: if second_try: self.error.emit(str(e)) else: raise Exception else: self.success.emit()
def step_impl(context): c = gpg.Context(armor=True) context.gpgdir = TemporaryDirectory() c.home_dir = context.gpgdir.name userid = "backup-" + ''.join([ random.choice(string.ascii_letters + string.digits) for n in range(10) ]) c.create_key(userid, algorithm="rsa3072", expires_in=31536000, encrypt=True) context.public_key = c.key_export_minimal(pattern=userid) context.private_key = c.key_export_secret(pattern=userid)
def receive(serverurl, keystring): pattern8 = re.compile(r"(^[0-9a-fA-F]{8}$)|(^[0-9a-fA-F]{16}$)") if re.match(pattern8, keystring) is None: fail("Invalid key pattern!") server = Server(serverurl) fullKey = server.get(keystring) if fullKey in [None, []]: fail("No keys found") c = gpg.Context() c.op_import(fullKey.encode()) result = c.op_import_result() if result is None: fail("Could not import contact") print_debug(result)
def main(args): if args.jira_username is None or args.jira_password is None: netrc_path = os.path.expanduser(args.netrc_gpg_path) if not os.path.isfile(netrc_path): logging.error("netrc file %s not found", netrc_path) sys.exit(1) with gpg.Context() as c: with open(netrc_path) as f: login_info = login_info_from_netrc(c.decrypt(f)[0], host_from_jira_server( args.jira_api_server)) user, password = login_info["user"], login_info["password"] else: user, password = args.jira_username, args.jira_password try: authed_jira = jira.JIRA(args.jira_api_server, basic_auth=(user, password)) except jira.exceptions.JIRAError as e: if "CAPTCHA_CHALLENGE" in str(e): logging.error( ("JIRA requires a CAPTCHA, please log in to %s in the browser to solve them" "(log out first if you are already logged in)." "Please also check that the PASSWORD used is correct."), args.jira_api_server) def ask(msg, options, default="y"): def getletter(msg): return "".join(input(msg).lower().strip()[:1]) reply = getletter(msg) while (reply not in options and not (default and reply == "")): reply = getletter(msg) return (reply if reply else default) reply = ask("Open jira in browser (Y, n)? ", ["y", "n"], default="y") if reply == "y": import webbrowser webbrowser.open(args.jira_api_server) else: logging.warn("Not opening browser, please login to %s manually.", args.jira_api_server) else: raise all_bugs = authed_jira.search_issues('type=Bug OR type=Sub-bug', fields="key", maxResults=False) for issue in all_bugs: print (issue.key)
def rawkey2infos(key_fo): pb_dir = tempfile.mkdtemp() keyinfos = [] with pubring_dir(pb_dir), gpg.Context() as ctx: ctx.op_import(key_fo) for key in ctx.keylist(): subkey = _extract_signing_subkey(key) if subkey is None: continue keyinfos.append(Key(key, subkey)) ctx.armor = True for info in keyinfos: with gpg.Data() as sink: ctx.op_export(info.id_, 0, sink) sink.seek(0, os.SEEK_SET) info.raw_key = sink.read() dnf.util.rm_rf(pb_dir) return keyinfos
def __init__(self, armor=True, home_dir=None, engine_path=None, passphrase=None): self._gpg = gpg.Context(armor=armor) if home_dir is not None or engine_path is not None: self._gpg.set_engine_info(self._gpg.protocol, file_name=engine_path, home_dir=home_dir) if passphrase is not None: self._passphrase = passphrase self._gpg.pinentry_mode = gpg.constants.PINENTRY_MODE_LOOPBACK self._gpg.set_passphrase_cb(passphrase) else: self._passphrase = None
def setUpClass(cls): """Set up the class""" super(ModelBuildingTestCase, cls).setUpClass() cls.gpg_homedir = tempfile.mkdtemp() cls.key_passphrase = _UNSAFE_KEY_PASSPHRASE cls.gpg_context = gpg.Context( home_dir=cls.gpg_homedir, armor=True, offline=True, pinentry_mode=gpg.constants.PINENTRY_MODE_LOOPBACK, ) import_secret_key(cls.gpg_homedir, TESTING_PRIVATE_KEY_FILE, passphrase=_UNSAFE_KEY_PASSPHRASE) signing_key = cls.gpg_context.get_key( _UNSAFE_KEY_FOR_TESTING_FINGERPRINT) add_trusted_keys_to_gpg_home_dir(cls.gpg_homedir) cls._signing_fingerprint = signing_key.fpr
def search(serverurl, searchstring): server = Server(serverurl) print_debug(server.serverurl) keys = server.index(searchstring) if keys in [None, []]: fail("No keys found") else: keysToImport = server.getchoice(keys) c = gpg.Context() for key in keysToImport: c.op_import(key.fullKey.encode()) result = c.op_import_result() if result is None: fail("Could not import contact") print_debug(result)
def __init__(self, ssm_path: str, recipients: List[str], bindir: str = None): if bindir is None: bindir = os.getcwd() + "/bin" if not os.path.exists(bindir): os.makedirs(bindir) self.bindir = bindir self.ssm_path = ssm_path self.ssm = boto3.client("ssm") self.recipients = recipients c = gpg.Context(armor=True) self.gpgdir = TemporaryDirectory() c.home_dir = self.gpgdir.name self.get_gpg_keys(c) self.gpg_context = c
def import_key_and_check_status(self, key): """Import a GnuPG key and check that the operation was successful. :param str key: A string specifying the key's filepath from ``Common.paths`` :rtype: bool :returns: ``True`` if the key is now within the keyring (or was previously and hasn't changed). ``False`` otherwise. """ if gpgme_support: with gpg.Context() as c: c.set_engine_info(gpg.constants.protocol.OpenPGP, home_dir=self.paths['gnupg_homedir']) impkey = self.paths['signing_keys'][key] try: c.op_import(gpg.Data(file=impkey)) except: return False else: result = c.op_import_result() if result and self.fingerprints[key] in result.imports[ 0].fpr: return True else: return False else: success = False p = subprocess.Popen([ '/usr/bin/gpg', '--status-fd', '2', '--homedir', self.paths['gnupg_homedir'], '--import', self.paths['signing_keys'][key] ], stderr=subprocess.PIPE) p.wait() for output in p.stderr.readlines(): match = gnupg_import_ok_pattern.match(output) if match: if match.group().find(self.fingerprints[key]) >= 0: success = True break return success
def seal(file_path, recipients): """ sign and encrypt file_path to the recipents """ try: c = gpg.Context(armor=True) c.signers = list(c.keylist(pattern=None, secret=True)) seal_list = [] # prepare the list for recipient in recipients: keys = c.keylist(pattern=recipient) chosen_keys = get_selected_key(list(keys)) seal_list.extend(chosen_keys) # print the list print("The following recipients were selected:") for sno, key in enumerate(seal_list): print(str(sno+1) + ")", key.uids[0].uid, key.fpr) # encrypt seal_path = file_path+".sealed" with open(file_path) as infile: with open(seal_path, "w") as outfile: try: _cyphertext, _result, _sign_result = c.encrypt( infile, recipients=seal_list, sign=True, sink=outfile) except gpg.errors.InvalidRecipients: print("Some of the recipients are not trusted." " Do you want to proceed anyway[y/N]", end='>') answer = input().lower() if answer == 'y' or answer == 'yes': _cyphertext, _result, _sign_result = c.encrypt( infile, recipients=seal_list, sign=True, sink=outfile, always_trust=True) else: exit(3) except BaseException: if os.environ['DEBUG'] == 'yes': raise exit(2)
def get_testing_gpg_homedir_and_context(): """Get a temporary home directory, gpg key and fingerprint for testing signing logic Yields: gpg_home_dir, new_key (for signing), fingerprint (of signing key) """ with get_temporary_directory() as gpg_home_dir: # gpg_home_dir is now fsync'ed with gpg.Context( home_dir=gpg_home_dir, armor=True, offline=True, pinentry_mode=gpg.constants.PINENTRY_MODE_LOOPBACK, ) as ctx: import_secret_key(gpg_home_dir, TESTING_PRIVATE_KEY_FILE, _UNSAFE_KEY_PASSPHRASE) test_key = ctx.get_key(_UNSAFE_KEY_FOR_TESTING_FINGERPRINT) fingerprint = test_key.fpr yield gpg_home_dir, test_key, fingerprint
def GPG(cur, homedir=None, keyid=None): g = gpg.Context(home_dir=homedir) if not keyid: # We don't have a key specified, so we need to generate one and update the config. s = ( 'This signature and signing key were automatically generated using Autopkg from OpTools: ' 'https://git.square-r00t.net/OpTools/') g.sig_notation_add('*****@*****.**', s, gpg.constants.sig.notation.HUMAN_READABLE) userid = 'Autopkg Signing Key ({0}@{1})'.format( os.getenv('SUDO_USER', os.environ['USER']), gethostname()) params = { #'algorithm': 'ed25519', 'algorithm': 'rsa4096', 'expires': False, 'expires_in': 0, 'sign': True, 'passphrase': None } keyid = g.create_key(userid, **params).fpr # https://stackoverflow.com/a/50718957 q = {} for col in ('keyid', 'homedir'): if sqlite3.sqlite_version_info > (3, 24, 0): q[col] = ("INSERT INTO config (directive, value) " "VALUES ('gpg_{0}', ?) " "ON CONFLICT (directive) " "DO UPDATE SET value = excluded.value").format(col) else: cur.execute( "SELECT id FROM config WHERE directive = 'gpg_{0}'".format( col)) row = cur.fetchone() if row: q[col] = ( "UPDATE config SET value = ? WHERE id = '{0}'").format( row['id']) else: q[col] = ( "INSERT INTO config (directive, value) VALUES ('gpg_{0}', ?)" ).format(col) cur.execute(q[col], (locals()[col], )) return (keyid, g)
def step_impl(context): c = gpg.Context(armor=True) gpgdir = TemporaryDirectory() c.home_dir = gpgdir.name assert_that( len(context.private_key), greater_than(64), "private key is too short to be real", ) assert_that( len(context.encrypted_file_contents), greater_than(64), "encrypted file is too short to be real ", ) c.key_import(context.private_key) plaintext, result, verify_result = c.decrypt( context.encrypted_file_contents) assert_that(plaintext, equal_to(context.test_data))