def test_decrypt_unsigned_message(): from pgpy import PGPKey, PGPMessage from pgpy.errors import PGPError # these keys are small because the regression test doesn't really need the security # if you're reading this, *DO NOT GENERATE RSA KEYS THIS SMALL* # also, it's probably better to sign-then-encrypt rather than encrypt-then-sign decrypt_key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xcA4BFlKzk4BAgDL9E6Lpzq9yNhRP49HXeOSYTz4DPI1A2wxwI97qjZFsJ2lJ2aV\n" \ "SYFpbuS6DEPaya+98HQ6xM7o2PhbUnHqcXHzABEBAAEAAf9U/XOVwpQ57e4mvWPJ\n" \ "i5h/sUGk5FAyQ0Dc4q9oCyAenaIIe5npbsR+oKmUHwJ5wWgfrTaxvAkBl15kMtSN\n" \ "VItBAQDv/8BdIdW2Bc9+qvCtC2xiUJ/3Rd+eyXMZhn4VMdA8sQEA2Y1aRBpWjHo9\n" \ "g9KydxAewt8LUwchRHeonMmILuZ58eMBALP8euss11ELnjDOLrgRP2swnOTTTk3b\n" \ "P6aV8/rbcEXOUgPNG1JlZ3Jlc3NvIEVuY3J5cHRlciAoUFIjMTgzKcJrBBMBAgAV\n" \ "BQJZSs6CAhsOAgsHAhUCAhYAAh4BAAoJEA2I8KkOVzh/+IMCAI308quFk/lJXPF/\n" \ "bpvwwgFa9bRdIzl07Qu+3oQcEm+1cu6ivznewIEmQclSUpSLjXrS/LysQSAQye+J\n" \ "PgSEalQ=\n" \ "=Sg/Y\n" \ "-----END PGP PRIVATE KEY BLOCK-----\n" sign_key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xcA4BFlKzkMBAgDQZA3bao1qo3XkuUDOaFm1x5TkAAMUUUxtmj+dSR0wl7uRzxWm\n" \ "8naFpsJ1Mah/I8RlS1oZizaDI7BzbOvGUGjLABEBAAEAAf95RBAQQ/QhPxfmzqrY\n" \ "sj6qGocZGqywERMxoJYuOBLFaCjdT8xk0syI0LOCetwDmUWerUPWO52w9T5Gj295\n" \ "YUDpAQD7DSmifDMssvG5F9JYWdKobEwWxVsjyaYR/vbH/1Iy3QEA1H+e66Jz1ERl\n" \ "yPLyl4E5chwO2l+VMxiFod3Dvo8C68cA/0GWJIdK0NzSNZwS6wFabZg2R1pZWxJJ\n" \ "B0tsI0EqbUgNTiXNGFJlZ3Jlc3NvIFNpZ25lciAoUFIjMTgzKcJoBBMBAgASBQJZ\n" \ "Ss53AhsCAhUCAhYAAh4BAAoJED6S3OqHJjksTzQCAM73UuXFtM2qXp4zfOGYEMsj\n" \ "gcKFuFFLyNOhPZo6REeJC7o2+9d7Mwys8wVNTuS3D3o1h49QpYYNjYlgNSZ85pU=\n" \ "=DBkI\n" \ "-----END PGP PRIVATE KEY BLOCK-----\n" msg = "-----BEGIN PGP MESSAGE-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xA0DAAIBPpLc6ocmOSwAwUwDDYjwqQ5XOH8BAfwOTH6C/lk5bQevArYnrf0q3Dde\n" \ "JDjM/otBckiTS8kvFz1XFfQhIDkZl+fDcRwDFNe9+JKLqOM4jU6FIUwToYgz0ksB\n" \ "f6iZ80U0dzHGtvmEzYSnsYWAglik0ch/E9tyNq/lryrLnrxWu7V26wPfI1TISuKd\n" \ "U+w1HPGoH8ugo6GkeqBdeED6gJfKEm1qgrHCXAQAAQIABgUCWUrVMQAKCRA+ktzq\n" \ "hyY5LLcHAgDHYjKVbpd5/FV4+CZ0H5yTnrD/vZ+QebDC7CmOM7f1Q5L1AdG/K1rr\n" \ "+Ud/YHq3NVk5UGU0LDfjdBwVaJmOjEUx\n" \ "=ITfp\n" \ "-----END PGP MESSAGE-----\n" dkey, _ = PGPKey.from_blob(decrypt_key) skey, _ = PGPKey.from_blob(sign_key) encmsg = PGPMessage.from_blob(msg) # this should work decmsg = dkey.decrypt(encmsg) assert decmsg.message == "Regression Test for PR#183" # this should raise PGPError, not PGPDecryptionError with pytest.raises(PGPError): skey.decrypt(encmsg)
def test_decrypt_unsigned_message(): from pgpy import PGPKey, PGPMessage from pgpy.errors import PGPError # these keys are small because the regression test doesn't really need the security # if you're reading this, *DO NOT GENERATE RSA KEYS THIS SMALL* # also, it's probably better to sign-then-encrypt rather than encrypt-then-sign decrypt_key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xcA4BFlKzk4BAgDL9E6Lpzq9yNhRP49HXeOSYTz4DPI1A2wxwI97qjZFsJ2lJ2aV\n" \ "SYFpbuS6DEPaya+98HQ6xM7o2PhbUnHqcXHzABEBAAEAAf9U/XOVwpQ57e4mvWPJ\n" \ "i5h/sUGk5FAyQ0Dc4q9oCyAenaIIe5npbsR+oKmUHwJ5wWgfrTaxvAkBl15kMtSN\n" \ "VItBAQDv/8BdIdW2Bc9+qvCtC2xiUJ/3Rd+eyXMZhn4VMdA8sQEA2Y1aRBpWjHo9\n" \ "g9KydxAewt8LUwchRHeonMmILuZ58eMBALP8euss11ELnjDOLrgRP2swnOTTTk3b\n" \ "P6aV8/rbcEXOUgPNG1JlZ3Jlc3NvIEVuY3J5cHRlciAoUFIjMTgzKcJrBBMBAgAV\n" \ "BQJZSs6CAhsOAgsHAhUCAhYAAh4BAAoJEA2I8KkOVzh/+IMCAI308quFk/lJXPF/\n" \ "bpvwwgFa9bRdIzl07Qu+3oQcEm+1cu6ivznewIEmQclSUpSLjXrS/LysQSAQye+J\n" \ "PgSEalQ=\n" \ "=Sg/Y\n" \ "-----END PGP PRIVATE KEY BLOCK-----\n" sign_key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xcA4BFlKzkMBAgDQZA3bao1qo3XkuUDOaFm1x5TkAAMUUUxtmj+dSR0wl7uRzxWm\n" \ "8naFpsJ1Mah/I8RlS1oZizaDI7BzbOvGUGjLABEBAAEAAf95RBAQQ/QhPxfmzqrY\n" \ "sj6qGocZGqywERMxoJYuOBLFaCjdT8xk0syI0LOCetwDmUWerUPWO52w9T5Gj295\n" \ "YUDpAQD7DSmifDMssvG5F9JYWdKobEwWxVsjyaYR/vbH/1Iy3QEA1H+e66Jz1ERl\n" \ "yPLyl4E5chwO2l+VMxiFod3Dvo8C68cA/0GWJIdK0NzSNZwS6wFabZg2R1pZWxJJ\n" \ "B0tsI0EqbUgNTiXNGFJlZ3Jlc3NvIFNpZ25lciAoUFIjMTgzKcJoBBMBAgASBQJZ\n" \ "Ss53AhsCAhUCAhYAAh4BAAoJED6S3OqHJjksTzQCAM73UuXFtM2qXp4zfOGYEMsj\n" \ "gcKFuFFLyNOhPZo6REeJC7o2+9d7Mwys8wVNTuS3D3o1h49QpYYNjYlgNSZ85pU=\n" \ "=DBkI\n" \ "-----END PGP PRIVATE KEY BLOCK-----\n" msg = "-----BEGIN PGP MESSAGE-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xA0DAAIBPpLc6ocmOSwAwUwDDYjwqQ5XOH8BAfwOTH6C/lk5bQevArYnrf0q3Dde\n" \ "JDjM/otBckiTS8kvFz1XFfQhIDkZl+fDcRwDFNe9+JKLqOM4jU6FIUwToYgz0ksB\n" \ "f6iZ80U0dzHGtvmEzYSnsYWAglik0ch/E9tyNq/lryrLnrxWu7V26wPfI1TISuKd\n" \ "U+w1HPGoH8ugo6GkeqBdeED6gJfKEm1qgrHCXAQAAQIABgUCWUrVMQAKCRA+ktzq\n" \ "hyY5LLcHAgDHYjKVbpd5/FV4+CZ0H5yTnrD/vZ+QebDC7CmOM7f1Q5L1AdG/K1rr\n" \ "+Ud/YHq3NVk5UGU0LDfjdBwVaJmOjEUx\n" \ "=ITfp\n" \ "-----END PGP MESSAGE-----\n" dkey, _ = PGPKey.from_blob(decrypt_key) skey, _ = PGPKey.from_blob(sign_key) encmsg = PGPMessage.from_blob(msg) # this should work decmsg = dkey.decrypt(encmsg) assert decmsg.message == "Regression Test for PR#183" # this should raise PGPError, not PGPDecryptionError with pytest.raises(PGPError): skey.decrypt(encmsg)
def check_mailbox_password(key, password, access_token): """ Make sure the password is valid by decrypting the access token. Parameters ---------- key: Bytes PGP Private key password: String access_token: String Access token as an encrypted PGP message Returns ------- token: String """ if not key: raise ValueError("Missing private key") if not password: raise ValueError("Missing password") if not access_token: raise ValueError("Missing access token") msg = PGPMessage.from_blob(access_token) pk, _ = PGPKey.from_blob(key) if IS_PY3 and isinstance(password, bytes): password = password.decode() with pk.unlock(password) as uk: return bytes(uk.decrypt(msg).message)
def list_packets(self, keydata): # NOTE: while is known how to get the packets from PGPKey, # use gpg only here import subprocess key, _ = PGPKey.from_blob(keydata) keypath = self._save_key_to_file(key) sp = subprocess.Popen(['/usr/bin/gpg', '--list-packets', keypath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = sp.communicate() if sys.version_info >= (3, 0): out = out.decode() packets = [] lines = [] last_package_type = None for rawline in out.splitlines(): line = rawline.strip() c = line[0:1] if c == "#": continue if c == ":": i = line[1:].find(c) if i != -1: ptype = line[1:i + 1] pvalue = line[i + 2:].strip() if last_package_type is not None: packets.append(last_package_type + (lines, )) lines = [] last_package_type = (ptype, pvalue) else: assert last_package_type, line lines.append(line) else: packets.append(last_package_type + (lines, )) return packets
def test_pubkey_subkey_parent(): from pgpy import PGPKey # import this small key that has a subkey keyblob = ('-----BEGIN PGP PRIVATE KEY BLOCK-----\n' 'Version: PGPy v0.4.2\n' '\n' 'xcA4BFlULU4BAgDeq2bKPPOBzdgd1WF3RBQ0E0kkZbTfpgZjamDzdb6gfQ5TcBhs\n' 'drI4XpxWOV3DorbsZ8Usj4zHx/XmLNCmxwqvABEBAAEAAgCSO76l0qGY/baQ4THB\n' 'QdSC3qeKX8EJn99SKurA+PLYMg6IxLGBpWYIK8tT68xpqQ5ZwE9GodZ2QjfOVz2R\n' 'o4IBAQD/UjtthEtyiMA1CDCPEksfIyd0QDjt82C19MSeqau8WQEA30LydxkjlvgH\n' 'u5/uWVGqoFWhhfw5hDrYy72L6EbCfkcA/2csk7uGw/yg2MDUTlDwdokn1DLGkt/+\n' 'Q/fPAMYvX6gvVoXNFVJlZ3Jlc3NvIChJc3N1ZSAjMTk0KcJrBBMBAgAVBQJZVC3O\n' 'AhsDAgsHAhUCAhYAAh4BAAoJEC4sMTkKIj+F8ywB/AqaNHwi8xM1Rg99mOSib1zi\n' 'jlXALY8pOrNU7Nqtc/6oks+49WeVW5zpE1vl1JPm2WYzvCEnE1KffdyjNR0bQ1XH\n' 'wDgEWVQtUQECAKsWCdSRh6YDP9yuSonfHpBfUzRD/EQvpNnUDiTclV9w6RPMZYk9\n' 'o5oUQTumPKnznsovLpNmIm48DCALMzdTzH0AEQEAAQACAJDfsKNYOM3Toph03pmx\n' 'XmhS0FpJ16zFy4rJjtCYGcUerUqRQ1ehXIY9Ig9J5LitJXThrP4dvUlRCWUcxxl6\n' '9eEBANOiM8ktXW0bPZfBKunWn7ajA0PMBKG8p2d9iBCawBbbAQDO88L8V0cxCRvH\n' '8L1J4gsttPWDOnhw5z8Dq4Zv5U3thwD/WwE0miqfEpYAmkhc0g7lHf6l7qo+SrUZ\n' 'ZKl0GLPLKKFRscK9BBgBAgAJBQJZVC3mAhsMAGgJEC4sMTkKIj+FXSAEGQECAAYF\n' 'AllULeYACgkQCK0qxtsEtqzY7QIAoayZGB78eaImQVOpTLX2jnaDR2UY7NtUy6YI\n' 'XMSumCeZj+n+BexmUm6x2kqg0FJLRwAE4i+rnvFA0HHX40/9d221AgCzUxHuHjKP\n' 'b5wNW20vanc6b6ZMi52MyhluXAIdnvgPkPEzVIS+gGOX2DeT4TXAdosKfD1o5qS7\n' 'ANRbocmpDuO3\n' '=UjzO\n' '-----END PGP PRIVATE KEY BLOCK-----\n') privkey, _ = PGPKey.from_blob(keyblob) pubkey = privkey.pubkey assert pubkey.subkeys['08AD2AC6DB04B6AC'].parent is pubkey
def test_pubkey_subkey_parent(): from pgpy import PGPKey # import this small key that has a subkey keyblob = ('-----BEGIN PGP PRIVATE KEY BLOCK-----\n' 'Version: PGPy v0.4.2\n' '\n' 'xcA4BFlULU4BAgDeq2bKPPOBzdgd1WF3RBQ0E0kkZbTfpgZjamDzdb6gfQ5TcBhs\n' 'drI4XpxWOV3DorbsZ8Usj4zHx/XmLNCmxwqvABEBAAEAAgCSO76l0qGY/baQ4THB\n' 'QdSC3qeKX8EJn99SKurA+PLYMg6IxLGBpWYIK8tT68xpqQ5ZwE9GodZ2QjfOVz2R\n' 'o4IBAQD/UjtthEtyiMA1CDCPEksfIyd0QDjt82C19MSeqau8WQEA30LydxkjlvgH\n' 'u5/uWVGqoFWhhfw5hDrYy72L6EbCfkcA/2csk7uGw/yg2MDUTlDwdokn1DLGkt/+\n' 'Q/fPAMYvX6gvVoXNFVJlZ3Jlc3NvIChJc3N1ZSAjMTk0KcJrBBMBAgAVBQJZVC3O\n' 'AhsDAgsHAhUCAhYAAh4BAAoJEC4sMTkKIj+F8ywB/AqaNHwi8xM1Rg99mOSib1zi\n' 'jlXALY8pOrNU7Nqtc/6oks+49WeVW5zpE1vl1JPm2WYzvCEnE1KffdyjNR0bQ1XH\n' 'wDgEWVQtUQECAKsWCdSRh6YDP9yuSonfHpBfUzRD/EQvpNnUDiTclV9w6RPMZYk9\n' 'o5oUQTumPKnznsovLpNmIm48DCALMzdTzH0AEQEAAQACAJDfsKNYOM3Toph03pmx\n' 'XmhS0FpJ16zFy4rJjtCYGcUerUqRQ1ehXIY9Ig9J5LitJXThrP4dvUlRCWUcxxl6\n' '9eEBANOiM8ktXW0bPZfBKunWn7ajA0PMBKG8p2d9iBCawBbbAQDO88L8V0cxCRvH\n' '8L1J4gsttPWDOnhw5z8Dq4Zv5U3thwD/WwE0miqfEpYAmkhc0g7lHf6l7qo+SrUZ\n' 'ZKl0GLPLKKFRscK9BBgBAgAJBQJZVC3mAhsMAGgJEC4sMTkKIj+FXSAEGQECAAYF\n' 'AllULeYACgkQCK0qxtsEtqzY7QIAoayZGB78eaImQVOpTLX2jnaDR2UY7NtUy6YI\n' 'XMSumCeZj+n+BexmUm6x2kqg0FJLRwAE4i+rnvFA0HHX40/9d221AgCzUxHuHjKP\n' 'b5wNW20vanc6b6ZMi52MyhluXAIdnvgPkPEzVIS+gGOX2DeT4TXAdosKfD1o5qS7\n' 'ANRbocmpDuO3\n' '=UjzO\n' '-----END PGP PRIVATE KEY BLOCK-----\n') privkey, _ = PGPKey.from_blob(keyblob) pubkey = privkey.pubkey assert pubkey.subkeys['08AD2AC6DB04B6AC'].parent is pubkey
def test_verify_subkey_revocation_signature(): keyblob = ('-----BEGIN PGP PUBLIC KEY BLOCK-----\n' '\n' 'mI0EWgtKbAEEAOEjq2UsapzI996tHhvGB7mJTo1sneUso20vz5VluECI0Xv0nr0j\n' 'BfknMFNeuPRR5sopgnrYT2ezJxp60D1NFaKgDh0z0qv9spk9FTP4YtaE5pfZRk3l\n' 'iGgyY7WiJBhKLb7ne3PeG8mtju4T+9ejbN4hVx1Vz9WHKkLGeBGkOcYZABEBAAG0\n' 'HVRlc3QgUmV2b2NhdGlvbiA8YWJjQGRlZi5naGk+iM4EEwEIADgWIQRIuXHQYB9/\n' 'm0hHY/8zq5Y87Iwq4QUCWgtKbAIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAK\n' 'CRAzq5Y87Iwq4RKuA/46Zg3OSmRPJJNQegoDGLGwj81sgrLFPVDV2dSAxYPiGH3j\n' 'JNM760NS51FLHQvxwa9XV9/4xzL9jqsV8vD+lX5aphZS6h2olPAy9CP2FK8KFrv1\n' 'Rap2y9D68LStDv2jFyEYEGCCvon3Ff6O2PxwG98xkaskBPH6knGjK6rrMvYI/7iN\n' 'BFoLSmwBBACbGvXVtDH4aTJ3UbN/3UnLKb05ogmZDpkx8A2qGnUu1QvIxqi56emU\n' 'TfbxKv8jne0qas0IJ1OWrcTAuPvwgH4TJERAkngxzdYXR6ZHEO3/L8s0XSLobW5E\n' 'nsGnFw/PG5Lrxv1YA7nBlCKennrlaU9iiUguOUK7SW7To1SOojTOcQARAQABiLYE\n' 'KAEIACAWIQRIuXHQYB9/m0hHY/8zq5Y87Iwq4QUCWgtKuAIdAwAKCRAzq5Y87Iwq\n' '4eFnA/4oOnM7kjgIYqs2TgAxuddMabx1US9yYZDG097Nxfw1DFJoFOg4ozrrWNRz\n' 'F3AHo7Ocue288VYIJtjH4KB2vGAYdWq8j6bywW7t4Be2WsU4MCJqETxS+3Gv65B6\n' 'NBq4Y8lJvKO/cwsqYI6XWsJsmnVns0XOdv/k6ZouVdpUu5Fpr4i2BBgBCAAgFiEE\n' 'SLlx0GAff5tIR2P/M6uWPOyMKuEFAloLSmwCGwwACgkQM6uWPOyMKuFrOAP/ZemA\n' 'yfU6zSfiReQ5fsiQhiy2jZx+JVweZ0ESgDuIvT4tlB4WK87OcITd40rTalGezRuE\n' 'fhi3IcnDc7L+kBGNhP3IY8IFVNYGqfowIYLl/RX+3BUjuaDpunO9kIBrhm0WrC6Y\n' '+padVqwTFNFteQR0N9BW1qNf7HB20BCaElxGCuI=\n' '=EoFv\n' '-----END PGP PUBLIC KEY BLOCK-----\n') pubkey, _ = PGPKey.from_blob(keyblob) subkey = pubkey.subkeys['8ABD4FB3046BBCF8'] revsig = subkey._signatures[1] assert pubkey.verify(subkey, revsig)
def _verify_and_import_uid_packet(self, primary_key: PGPKey, uid_packet: bytes, expected_hash: str) -> None: actual_serialized_hash = sha256(uid_packet).hex() if not actual_serialized_hash == expected_hash: # hashes for the content do not match return imported_key, _ = PGPKey.from_blob(uid_packet) if not imported_key.fingerprint == primary_key.fingerprint: # Primary key material on the two keys does not match. They don't belong together. return if not KeyStore._verify_legal_key_with_single_userid(imported_key): # key failed one of the validity tests return if not primary_key.verify(imported_key.userids[0]): # Primary key did not sign userid. # This check was already performed via the self-signature check on imported_key and the fingerprint # match with primary_key before. return new_userid: PGPUID = imported_key.userids[0] self._transplant_uid(new_userid, primary_key)
def extract_key(self, pubkey): """ Build the PGP private key from the corresponding public key and this firmware key material """ assert not self.locked assert pubkey.is_public # create parent key privkey = self._create_private_key(pubkey, False) if not privkey: privkey = Firmware._nosecrete_private_key(pubkey._key) # take user IDs with their signatures from the public key for uid in pubkey.userids: privkey._uids.append(uid) # extract all sub keys for sk in pubkey.subkeys.values(): key = self._create_private_key(sk) if not key: logging.warning("Subkey not present in firmware: {}".format(sk.fingerprint)) continue privkey._children[key.fingerprint.keyid] = key key._parent = privkey # reload key so every field is correctly computed return PGPKey.from_blob(bytes(privkey))[0]
def test_load_from_bytearray(self, gpg_keyid_file): tkb = bytearray(os.stat(self.kf).st_size) with open(self.kf, 'rb') as tkf: tkf.readinto(tkb) key, _ = PGPKey.from_blob(tkb) assert key.fingerprint.keyid in gpg_keyid_file(self.kf.replace('tests/testdata/', ''))
def test_load_from_bytearray(self, kf): tkb = bytearray(os.stat(kf).st_size) with open(kf, 'rb') as tkf: tkf.readinto(tkb) key, _ = PGPKey.from_blob(tkb) assert key.fingerprint == _fingerprints[os.path.basename(kf)]
def get_keys(self) -> list: session = self.get_session() keys = session.query(Key).all() deserialized_keys = [] for key in keys: deserialized_key, other = PGPKey.from_blob(key.key) deserialized_keys.append(deserialized_key) return deserialized_keys
def test_load_from_bytearray(self, kf): tkb = bytearray(os.stat(kf).st_size) with open(kf, 'rb') as tkf: tkf.readinto(tkb) key, _ = PGPKey.from_blob(tkb) assert key.fingerprint == _fingerprints[os.path.basename(kf)]
def test_load_from_bytearray(self, gpg_keyid_file): tkb = bytearray(os.stat(self.kf).st_size) with open(self.kf, 'rb') as tkf: tkf.readinto(tkb) key, _ = PGPKey.from_blob(tkb) assert key.fingerprint.keyid in gpg_keyid_file( self.kf.replace('tests/testdata/', ''))
def _get_public_key(self, email): email = utils.str(email) r = yield self.api.keys('?Email={}'.format(email), blocking=False, response=responses.KeysResponse) self.PublicKeys[email] = [ PGPKey.from_blob(k.PublicKey)[0] for k in r.Keys ] return_value(r)
def test_load_from_bytes(self, kf, gpg_keyid_file): with open(kf, 'rb') as tkf: key, _ = PGPKey.from_blob(tkf.read()) # TODO: maybe store the fingerprint instead of relying on a particular version of GnuPG...? if 'ecc' in kf and gpg_ver < '2.1': assert key.fingerprint else: assert key.fingerprint.keyid in gpg_keyid_file( kf.replace('tests/testdata/', ''))
def validate_public_key(cls, v: Optional[str]) -> Optional[str]: from pgpy import PGPKey from pgpy.errors import PGPError if v: try: key, _ = PGPKey.from_blob(v.encode("utf-8")) except (ValueError, PGPError): raise ValueError("Invalid PGP public key: cannot load the key") if not key.is_public: raise ValueError("Invalid PGP public key: key is private") return v
def test_sig_timezone(): from pgpy import PGPKey, PGPSignature # from https://tools.ietf.org/html/draft-bre-openpgp-samples-00#section-2.2: alice_sec = '''-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Alice's OpenPGP Transferable Secret Key lFgEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U b7O1u10AAP9XBeW6lzGOLx7zHH9AsUDUTb2pggYGMzd0P3ulJ2AfvQ4RtCZBbGlj ZSBMb3ZlbGFjZSA8YWxpY2VAb3BlbnBncC5leGFtcGxlPoiQBBMWCAA4AhsDBQsJ CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE64W7X6M6deFelE5j8jFVDE9H444FAl2l nzoACgkQ8jFVDE9H447pKwD6A5xwUqIDprBzrHfahrImaYEZzncqb25vkLV2arYf a78A/R3AwtLQvjxwLDuzk4dUtUwvUYibL2sAHwj2kGaHnfICnF0EXEcE6RIKKwYB BAGXVQEFAQEHQEL/BiGtq0k84Km1wqQw2DIikVYrQrMttN8d7BPfnr4iAwEIBwAA /3/xFPG6U17rhTuq+07gmEvaFYKfxRB6sgAYiW6TMTpQEK6IeAQYFggAIBYhBOuF u1+jOnXhXpROY/IxVQxPR+OOBQJcRwTpAhsMAAoJEPIxVQxPR+OOWdABAMUdSzpM hzGs1O0RkWNQWbUzQ8nUOeD9wNbjE3zR+yfRAQDbYqvtWQKN4AQLTxVJN5X5AWyb Pnn+We1aTBhaGa86AQ== =n8OM -----END PGP PRIVATE KEY BLOCK----- ''' alice_key, _ = PGPKey.from_blob(alice_sec) class FixedOffset(datetime.tzinfo): def __init__(self, hours, name): self.__offset = datetime.timedelta(hours=hours) self.__name = name def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return datetime.timedelta(0) # America/New_York during DST: tz = FixedOffset(-4, 'EDT') # 2019-10-20T09:18:11-0400 when = datetime.datetime.fromtimestamp(1571577491, tz) pgpsig = alice_key.sign('this is a test', created=when) roundtrip = PGPSignature.from_blob(str(pgpsig)) assert pgpsig.created.utctimetuple() == roundtrip.created.utctimetuple()
def validate_pgp_public_key(cls, v: Optional[str]) -> Optional[PGPKey]: from base64 import urlsafe_b64decode from pgpy.errors import PGPError if v: try: public_key_str = urlsafe_b64decode(v) key, _ = PGPKey.from_blob(public_key_str) except (ValueError, PGPError): raise ValueError("Invalid PGP public key: cannot load the key") if not key.is_public: raise ValueError("Invalid PGP public key: key is private") return key return None
def load_pgp_key(raw_key): err_codes = ['4'] try: key, _ = PGPKey.from_blob(raw_key) return key, None except TypeError: err_msg = "Input key does not have a valid type, {}".format( session['firstname']) err_codes.append('1') return None, util.make_result(err_msg, err_codes) except ValueError: err_msg = "Input key is not a properly formed PGP block, {}".format( session['firstname']) err_codes.append('2') return None, util.make_result(err_msg, err_codes) except PGPError: err_msg = "De-armoring or parsing failed, {}".format( session['firstname']) err_codes.append('3') return None, util.make_result(err_msg, err_codes)
def _parse_keys_from_list_of_lines( lines: Iterable[str]) -> Generator[PGPKey, None, None]: start_markers = [ "-----BEGIN PGP PUBLIC KEY BLOCK-----", "-----BEGIN PGP PRIVATE KEY BLOCK-----" ] end_markers = [ "-----END PGP PUBLIC KEY BLOCK-----", "-----END PGP PRIVATE KEY BLOCK-----" ] current_token: str = "" for line in lines: if line.endswith("\n"): line = line.rstrip("\n") for start_marker in start_markers: if line == start_marker: current_token = "" # nosec current_token += line + "\n" for end_marker in end_markers: if line == end_marker: yield PGPKey.from_blob(current_token)[0]
def test_add_subkey(self, pkspec, skspec): if pkspec not in self.keys: pytest.skip( 'Keyspec {} not in keys; must not have generated'.format( pkspec)) alg, size = skspec if not alg.can_gen: pytest.xfail('Key algorithm {} not yet supported'.format(alg.name)) if isinstance(size, EllipticCurveOID) and ( (not size.can_gen) or size.curve.name not in _openssl_get_supported_curves()): pytest.xfail('Curve {} not yet supported'.format(size.curve.name)) key = self.keys[pkspec] subkey = PGPKey.new(*skspec) # before adding subkey to key, the key packet should be a PrivKeyV4, not a PrivSubKeyV4 assert isinstance(subkey._key, PrivKeyV4) assert not isinstance(subkey._key, PrivSubKeyV4) key.add_subkey(subkey, usage={KeyFlags.EncryptCommunications}) # now that we've added it, it should be a PrivSubKeyV4 assert isinstance(subkey._key, PrivSubKeyV4) assert key.verify(PGPKey.from_blob(bytes(subkey))) # self-verify with warnings.catch_warnings(): warnings.simplefilter('ignore') assert key.verify(subkey) sv = key.verify(key) assert sv assert subkey in sv if gpg: # try to verify with GPG self.gpg_verify_key(key)
def test_preference_unsupported_ciphers(): from pgpy import PGPMessage keyblob = ( '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' '\n' 'mQENBFtKbSQBCADDMwreTvJkDQkgB+n0GsNbMFKEjPYGKP365y5w+FlJ2zg69F3W\n' 'ituYFQcTwuge2XSh58k/XHln+MwjNc5cDQaWLtMuyJbRvLK+8MdpdYlzrlyrsgDI\n' 'L/1PAlGMVWB83Iu2kxqc0ppTxwsltAcvRJBE+9oSiWRACQviDmX5LeBmPoGqM93w\n' 'LeN3QT/tu26rxha374HPgSqqNR13r3xl7gQre+pA3jmNQqwzPnEmUKN3hO852NAw\n' 'QOPbf4yTCcbeZ6iZ/h0mW4DvbLiPbzUsXRvgTo3X/kzJD+ZnznvJvjcKrkXzaOAp\n' 'qt6Nd1LmWyv5h7gBYgBNaQONFeMl9MVBFUflABEBAAG0GnRlc3RrZXkgPHRlc3RA\n' 'ZXhhbXBsZS5jb20+iQFPBBMBCAA5AhsDAh4BAheAFiEEL7Bmz7+mS4Q3LDSMbIbe\n' 'TttFc4wFAltKbXsFCwoJCAcGFQoJCAsCBRYCAwEAAAoJEGyG3k7bRXOMI34IAINL\n' 'bYmZ95RgVX98+tjBAliV9xZaaxu4xpY8vz4pCwwFj9QBMxkzmITC1yb/Vav6pLFK\n' 'UISLGeOUqskVg9uQn8YGSnRaKoxetL894o0jGLyQF6ujF4OFhbfRlaLbNACDQqg0\n' 'bzV1E+s6RsnbwR7aFlOcgz5m/j7+c9t/BnZ4qOYBW85iLyzQA4BgTBSocdyom3EA\n' 'osCNY4tFuySFlOF34OLu1k8y9RP0KsJJptEdIwEqSxRKuQ5KTbopx9kvxVfOOwgy\n' 'RVYuP/OQrc/MQPGSC0Rmh/iCNEsTOIxcwnotmyRd8qDpw/EBj1a0iWxzPYOzXoEQ\n' 'Ff2ipWRkzS3AyWVJJxi5AQ0EW0ptJAEIAJXwfVD+3oSLPedMBvpfnveu/LjFvxJk\n' 'ohawApu63JzJNXoRpjeBhox073iEjeSbvq/pJ/+y0t6KkFZXoXgpqACGDNjPpojk\n' '6YTo6Da7GpyXefhKyH4IQ9Lbd9UIEhOKfktXTJfR/EoCZb+rmTm0WnjwkwOAVdQv\n' 'vuMRm8Hc39xn+Mt0CV+0KcYHhNfK+A2XU6bZkHuwaTzxTaotmeLeCgC+BA2Phwxp\n' 'BIhkSNE8ayYLN0VBPraw28xONzNV5e6f8RWNoGTDQxhZflmvIGz/XO5wo1DV1G0k\n' 'VIR49brAmrapqpCW7XWhuuupVbrpbjRUa+c4G03tySXQXUTdA3etH0EAEQEAAYkB\n' 'NgQYAQgAIBYhBC+wZs+/pkuENyw0jGyG3k7bRXOMBQJbSm0kAhsMAAoJEGyG3k7b\n' 'RXOMKbMIAKymk6Fe1qpjXtK56jpMurz1wBL0/twQbvtKQlgMBNdro0MX30xKGXh1\n' 'rCEIV3ls7CJnUm2NEeqFPzFZhsZS2FkgDXXT20K3S6nscv8xlF2z+jktK2RY6oCJ\n' 'Lgw447Rgjw5ARgW2XNrGRzapAf4KBgcyO1KtTCbjh8leg4Fs1O7B8EbiBvoeUJR0\n' 'wj2xNG4cOHoWN7Zjv8lLsJn60+ZbTeU25ghybmt7WjCs4ht7TZmamerLPzrFvP2c\n' 'ftLsb17HhrBPdfs42SsD8A816JDM7PcJWujlDV9FPJgoVjndK+4Jfpg9b4jOBA7J\n' '7zeGuobtKdS9Y97BVFNtTPZK66YUIEQ=\n' '=lGIy\n' '-----END PGP PUBLIC KEY BLOCK-----\n') pubkey, _ = PGPKey.from_blob(keyblob) msg = PGPMessage.new('asdf') with warnings.catch_warnings(): warnings.simplefilter('ignore') pubkey.encrypt(msg)
def _verify_keybase_signature(raw_pgp_sig_msg): # load the raw pgp message pgp_msg = PGPMessage.from_blob(raw_pgp_sig_msg) # load keybase's claimed public key # see: https://keybase.io/docs/server_security/our_merkle_key kb_public_key, _ = PGPKey.from_blob(KEYBASE_PGP_VERIFICATION_KEY) # verify it: https://pgpy.readthedocs.io/en/latest/examples.html#verifying-things f = io.StringIO() with redirect_stderr(f): # suppress unnecessary stdout verification_result = kb_public_key.verify(pgp_msg) if not verification_result: raise VerificationError( "API response did not verify with Keybase's public key") good_signatures = list(verification_result.good_signatures) if len(good_signatures) != 1: logger.error(f"good_signatures = {good_signatures}") raise VerificationError( f"Expected 1 valid signature, got {len(good_signatures)} from {specific_url}" ) return json.loads(good_signatures[0].subject)
def test_load_from_bytes(self, kf): with open(kf, 'rb') as tkf: key, _ = PGPKey.from_blob(tkf.read()) assert key.fingerprint == _fingerprints[os.path.basename(kf)]
def get_stored_key(armored_key: str) -> PGPKey: return PGPKey.from_blob(textwrap.dedent(armored_key))[0]
ciphers=[ SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES128 ], compression=[ CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP, CompressionAlgorithm.Uncompressed ]) # password protect private key key.protect("Password", SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256) # print private and public key private_key = str(key) public_key = str(key.pubkey) print(private_key) print(public_key) # encrypt message using public key message = pgpy.PGPMessage.new(" This is the message cleartext") encryptedmessage = str(PGPKey.from_blob(public_key)[0].encrypt(message)) print(encryptedmessage) ## decrypt using private key private_key = PGPKey.from_blob(private_key)[0] # reads in from string format with private_key.unlock('Password') as unlocked_private_key: result = unlocked_private_key.decrypt( PGPMessage.from_blob(encryptedmessage)) ##get cleartext to a variable plaintext = result.message print(plaintext)
def _default_PrivateKey(self): if not self.Auth: return key, _ = PGPKey.from_blob(self.Auth.EncPrivateKey) return key
rsa_priv.n = MPI(int(gpg['n'], 16)) rsa_priv.d = MPI(int(gpg['d'], 16)) rsa_priv.p = MPI(int(gpg['p'], 16)) rsa_priv.q = MPI(int(gpg['q'], 16)) rsa_priv.u = MPI(int(gpg['u'], 16)) rsa_priv._compute_chksum() restored_priv_key = PrivKeyV4() restored_priv_key.pkalg = PubKeyAlgorithm.RSAEncryptOrSign restored_priv_key.keymaterial = rsa_priv restored_priv_key.update_hlen() pgp_key = PGPKey() pgp_key._key = restored_priv_key public_key, _ = PGPKey.from_blob(gpg['public']) # fingerprint contains cration date so we need explicit copy this one pgp_key._key.created = public_key._key.created pgp_key.add_uid(public_key.userids[0], usage={ KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage }, hashes=[ HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512, HashAlgorithm.SHA224 ], ciphers=[ SymmetricKeyAlgorithm.AES256,
def test_load_from_bytes(self, kf): with open(kf, 'rb') as tkf: key, _ = PGPKey.from_blob(tkf.read()) assert key.fingerprint == _fingerprints[os.path.basename(kf)]
def test_ops_order(): from pgpy import PGPKey, PGPMessage # from https://tools.ietf.org/html/draft-bre-openpgp-samples-00#section-2.2: alice_sec = '''-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Alice's OpenPGP Transferable Secret Key lFgEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U b7O1u10AAP9XBeW6lzGOLx7zHH9AsUDUTb2pggYGMzd0P3ulJ2AfvQ4RtCZBbGlj ZSBMb3ZlbGFjZSA8YWxpY2VAb3BlbnBncC5leGFtcGxlPoiQBBMWCAA4AhsDBQsJ CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE64W7X6M6deFelE5j8jFVDE9H444FAl2l nzoACgkQ8jFVDE9H447pKwD6A5xwUqIDprBzrHfahrImaYEZzncqb25vkLV2arYf a78A/R3AwtLQvjxwLDuzk4dUtUwvUYibL2sAHwj2kGaHnfICnF0EXEcE6RIKKwYB BAGXVQEFAQEHQEL/BiGtq0k84Km1wqQw2DIikVYrQrMttN8d7BPfnr4iAwEIBwAA /3/xFPG6U17rhTuq+07gmEvaFYKfxRB6sgAYiW6TMTpQEK6IeAQYFggAIBYhBOuF u1+jOnXhXpROY/IxVQxPR+OOBQJcRwTpAhsMAAoJEPIxVQxPR+OOWdABAMUdSzpM hzGs1O0RkWNQWbUzQ8nUOeD9wNbjE3zR+yfRAQDbYqvtWQKN4AQLTxVJN5X5AWyb Pnn+We1aTBhaGa86AQ== =n8OM -----END PGP PRIVATE KEY BLOCK----- ''' bob_sec = '''-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Bob's OpenPGP Transferable Secret Key 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 =miES -----END PGP PRIVATE KEY BLOCK----- ''' alice_key, _ = PGPKey.from_blob(alice_sec) bob_key, _ = PGPKey.from_blob(bob_sec) msg = PGPMessage.new('this is a test') sig1 = alice_key.sign(msg) sig2 = bob_key.sign(msg) msg |= sig1 msg |= sig2 it = iter(msg) assert sig2.signer == next(it).signer # OPS 1 assert sig1.signer == next(it).signer # OPS 2 next(it) # skip contents assert sig1 == next(it) assert sig2 == next(it)
def _encrypt(data: str) -> str: msg = PGPMessage.new(data) pub_key_obj = PGPKey.from_blob(PUBKEY)[0] return str(pub_key_obj.encrypt(msg))
def test_load_from_bytes(self, gpg_keyid_file): with open(self.kf, 'rb') as tkf: key, _ = PGPKey.from_blob(tkf.read()) assert key.fingerprint.keyid in gpg_keyid_file( self.kf.replace('tests/testdata/', ''))
def _keydata2key(keydata): assert isinstance(keydata, str) kb64bytes = keydata.encode('ascii') kbytes = b64decode(kb64bytes) key, _ = PGPKey.from_blob(kbytes) return key
def import_keydata(self, keydata): key, _ = PGPKey.from_blob(keydata) self._load_key_into_kr(key) return key.fingerprint.keyid
def test_load_from_str(self, gpg_keyid_file): with open(self.kf, 'r') as tkf: key, _ = PGPKey.from_blob(tkf.read()) assert key.fingerprint.keyid in gpg_keyid_file(self.kf.replace('tests/testdata/', ''))