def abe(): uid = PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='*****@*****.**') with open('tests/testdata/abe.jpg', 'rb') as abef: abebytes = bytearray(os.fstat(abef.fileno()).st_size) abef.readinto(abebytes) uphoto = PGPUID.new(abebytes) # Abe is pretty oldschool, so he uses a DSA primary key # normally he uses an ElGamal subkey for encryption, but PGPy doesn't support that yet, so he's settled for RSA for now key = PGPKey.new(PubKeyAlgorithm.DSA, 1024) subkey = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 1024) key.add_uid(uid, usage={KeyFlags.Certify, KeyFlags.Sign}, hashes=[HashAlgorithm.SHA224, HashAlgorithm.SHA1], ciphers=[ SymmetricKeyAlgorithm.AES128, SymmetricKeyAlgorithm.Camellia128, SymmetricKeyAlgorithm.CAST5 ], compression=[CompressionAlgorithm.ZLIB]) key.add_uid(uphoto) key.add_subkey( subkey, usage={KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage}) return key
def temp_key(): u = PGPUID.new('User') k = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) k.add_uid(u, usage={KeyFlags.Certify, KeyFlags.Sign}, hashes=[HashAlgorithm.SHA1]) sk = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) k.add_subkey(sk, usage={KeyFlags.EncryptCommunications}) return k
def generate_rsa_key(uid='*****@*****.**', alg_key=PubKeyAlgorithm.RSAEncryptOrSign, alg_subkey=PubKeyAlgorithm.RSAEncryptOrSign, size=2048): # RSAEncrypt is deprecated, therefore using RSAEncryptOrSign # also for the subkey """Generate PGPKey object. :param alg_key: algorithm for primary key :param alg_subkey: algorithm for subkey :param size: key size :param uid: e-mail address :return: key :type alg_key: PubKeyAlgorithm :type alg_subkey: PubKeyAlgorithm :type size: integer :type uid: string :rtype: PGPKey """ # NOTE: default algorithm was decided to be RSA and size 2048. key = PGPKey.new(alg_key, size) # NOTE: pgpy implements separate attributes for name and e-mail address # is mandatory. # Here using e-mail address for the attribute name in order for # the uid to be the e-mail address. If name attribute is set to # empty string and email to the e-mail address, the uid will be ' # <e-mail address>', for instance: # " <*****@*****.**>" - which we do not want. uid = PGPUID.new(uid) # NOTE: it is needed to specify all arguments in current pgpy version. # FIXME: see which defaults we would like here key.add_uid(uid, usage={KeyFlags.Sign}, hashes=[HashAlgorithm.SHA512, HashAlgorithm.SHA256], ciphers=[ SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES128 ], compression=[ CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP, CompressionAlgorithm.Uncompressed ]) subkey = PGPKey.new(alg_subkey, size) key.add_subkey( subkey, usage={KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage}) logger.debug('Created key with fingerprint %s', key.fingerprint) return key
def test_new_key_deprecated_rsa_alg(self, key_alg_rsa_depr, recwarn): k = PGPKey.new(key_alg_rsa_depr, 512) w = recwarn.pop() assert str(w.message) == '{:s} is deprecated - generating key using RSAEncryptOrSign'.format(key_alg_rsa_depr.name) # assert w.filename == __file__ assert k.key_algorithm == PubKeyAlgorithm.RSAEncryptOrSign
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.name not in _openssl_get_supported_curves()): pytest.xfail('Curve {} not yet supported'.format(size.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) # self-verify assert key.verify(subkey) sv = key.verify(key) assert sv assert subkey in sv # try to verify with GPG self.gpg_verify_key(key)
def test_add_uid(self): key = PGPKey.new(pgpy.constants.PubKeyAlgorithm.RSAEncryptOrSign, 1024) add_uid(key, PGPUID.new("Name"), primary=True) self.assertEqual(len(key.userids), 1) self.assertIsNotNone(key.get_uid("Name")) self.assertTrue(key.get_uid("Name").is_primary) new_uid: PGPUID = key.get_uid("Name") self.assertIsNotNone(new_uid.selfsig) self.assertEqual(new_uid.signers.pop(), key.fingerprint.keyid) self.assertTrue(key.verify(new_uid)) uid_sig: PGPSignature = new_uid.selfsig self.assertEqual(uid_sig.created, get_uniform_time_as_datetime()) self.assertListEqual(uid_sig.cipherprefs, [pgpy.constants.SymmetricKeyAlgorithm.AES256]) self.assertListEqual( uid_sig.compprefs, [pgpy.constants.CompressionAlgorithm.Uncompressed]) self.assertListEqual(uid_sig.hashprefs, [pgpy.constants.HashAlgorithm.SHA512]) add_uid(key, PGPUID.new("Secondary"), False) self.assertEqual(len(key.userids), 2) self.assertFalse(key.get_uid("Secondary").is_primary)
def generate_pgp_key(name, email, comment, passphrase=None, armor=True): # We need to specify all of our preferences because PGPy doesn't have any built-in key preference defaults at this time. # This example is similar to GnuPG 2.1.x defaults, with no expiration or preferred keyserver key = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096) uid = PGPUID.new(name, email=email, comment=comment) key.add_uid(uid, usage={ KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage }, hashes=[ HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512, HashAlgorithm.SHA224 ], ciphers=[ SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES128 ], compression=[ CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP, CompressionAlgorithm.Uncompressed ]) # Protecting the key if passphrase: key.protect(passphrase, SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256) else: print('WARNING: Unprotected key', file=sys.stderr) pub_data = str(key.pubkey) if armor else bytes( key.pubkey) # armored or not sec_data = str(key) if armor else bytes(key) # armored or not return (pub_data, sec_data)
def test_encrypt_message_select_uid(self): # generate a temporary key with two UIDs, then encrypt a message u1 = PGPUID.new('UID One') u2 = PGPUID.new('UID Two') k = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) flags = { KeyFlags.Certify, KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage } k.add_uid(u1, usage=flags, hashes=[HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.AES128]) k.add_uid(u2, usage=flags, hashes=[HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.Camellia128]) emsg = k.pubkey.encrypt( PGPMessage.new('This message is about to be encrypted'), user='******') # assert that it was encrypted with Camellia128 and that we can decrypt it normally assert emsg._sessionkeys[0].decrypt_sk( k._key)[0] == SymmetricKeyAlgorithm.Camellia128 assert k.decrypt( emsg).message == 'This message is about to be encrypted'
def test_add_subkey(self, pkspec, skspec): 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: pytest.xfail('Curve {} not yet supported'.format(size.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) # self-verify assert key.verify(subkey) sv = key.verify(key) assert sv assert subkey in sv # try to verify with GPG self.gpg_verify_key(key)
def _gen_ssubkey(): # NOTE: the uid for the subkeys can be obtained with .parent, # but, unlike keys generated with gpg, it's not printed when imported # in gpg keyring and run --fingerprint. # in case of adding uid to the subkey, it raises currently some # exceptions depending on which are the arguments used, which are not # clear from the documentation. ssubkey = PGPKey.new(SKEY_ALG, KEY_SIZE) return ssubkey
def test_verify_invalid_sig(self, string, key_alg): # generate a keypair u = PGPUID.new('asdf') k = PGPKey.new(key_alg, key_alg_size[key_alg]) k.add_uid(u, usage={KeyFlags.Certify, KeyFlags.Sign}, hashes=[HashAlgorithm.SHA1]) # sign string with extra characters (this means k.pubkey.verify(string) will return false sig = k.sign(string + 'asdf') assert not k.pubkey.verify(string, sig)
def test_new_key(self, key_alg): # create a key and a user id and add the UID to the key uid = PGPUID.new('Hugo Gernsback', 'Science Fiction Plus', '*****@*****.**') key = PGPKey.new(key_alg, key_alg_size[key_alg]) key.add_uid(uid, hashes=[HashAlgorithm.SHA224]) # self-verify the key assert key.verify(key) self.gen_keys[key_alg] = key
def _generate_key(username: str): primary_key = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096) primary_key.add_uid( PGPUID.new(username), usage={KeyFlags.EncryptCommunications}, uidhashes=[HashAlgorithm.SHA512], ciphers=[SymmetricKeyAlgorithm.AES256], compression=[CompressionAlgorithm.ZIP] ) return primary_key
def test_verify_invalid_sig(self, pkspec, string): # test verifying an invalid signature u = PGPUID.new('asdf') k = PGPKey.new(*pkspec) k.add_uid(u, usage={KeyFlags.Certify, KeyFlags.Sign}, hashes=[HashAlgorithm.SHA1]) # sign the string with extra characters, so that verifying just string fails sig = k.sign(string + 'asdf') sv = k.pubkey.verify(string, sig) assert not sv assert sig in sv
def _create_test_key() -> Tuple[PGPKey, List[PGPUID]]: userids: List[PGPUID] = [ PGPUID.new("UID 1"), PGPUID.new("UID 2"), PGPUID.new("UID 3"), PGPUID.new("UID 4") ] key = PGPKey.new(pgpy.constants.PubKeyAlgorithm.RSAEncryptOrSign, 512) for userid in userids: key.add_uid(userid, selfsign=True) return key, userids
def _create_key() -> None: certifier = PGPKey.new(pgpy.constants.PubKeyAlgorithm.RSAEncryptOrSign, 512) certifier.add_uid(PGPUID.new("Can't sign without a UID-Self-Signature"), selfsign=True) key = PGPKey.new(pgpy.constants.PubKeyAlgorithm.RSAEncryptOrSign, 512) key.add_uid(PGPUID.new("First UID"), selfsign=True) key.add_uid(PGPUID.new("Second UID"), selfsign=True) key.add_uid(PGPUID.new("Duplicate UID"), selfsign=True) key.add_uid(PGPUID.new("Duplicate UID"), selfsign=True) # key.add_uid(PGPUID.new("Unsigned UID"), selfsign=False) certified_uid = PGPUID.new("Certified UID") key.add_uid(certified_uid, selfsign=True) key |= certifier.certify(key) certified_uid |= certifier.certify(key.get_uid("Certified UID")) print(certifier) print(key)
def abe(): uid = PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='*****@*****.**') with open('tests/testdata/abe.jpg', 'rb') as abef: abebytes = bytearray(os.fstat(abef.fileno()).st_size) abef.readinto(abebytes) uphoto = PGPUID.new(abebytes) # Abe is pretty oldschool, so he uses a DSA primary key # normally he uses an ElGamal subkey for encryption, but PGPy doesn't support that yet, so he's settled for RSA for now key = PGPKey.new(PubKeyAlgorithm.DSA, 1024) subkey = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 1024) key.add_uid(uid, usage={KeyFlags.Certify, KeyFlags.Sign}, hashes=[HashAlgorithm.SHA224, HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.AES128, SymmetricKeyAlgorithm.Camellia128, SymmetricKeyAlgorithm.CAST5], compression=[CompressionAlgorithm.ZLIB]) key.add_uid(uphoto) key.add_subkey(subkey, usage={KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage}) return key
def _gen_skey_usage_all(addr): seckey = PGPKey.new(SKEY_ALG, KEY_SIZE) # NOTE: pgpy implements separate attributes for name and e-mail # address. Name is mandatory. # Here e-mail address is used for the attribute name, # so that the uid is 'e-mail adress'. # If name attribute would be set to empty string # and email to the e-mail address, the uid would be # ' <e-mail address>', which we do not want. uid = PGPUID.new(addr) seckey.add_uid(uid, usage=SKEY_USAGE_ALL, **SKEY_ARGS) return seckey
def generate(username: str): primary_key = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096) primary_key.add_uid(PGPUID.new(username), usage={KeyFlags.EncryptCommunications}, uidhashes=[HashAlgorithm.SHA512], ciphers=[SymmetricKeyAlgorithm.AES256], compression=[CompressionAlgorithm.ZIP]) secho("Primary key, to be saved in server", fg=colors.BLUE) secho(primary_key.fingerprint, fg=colors.RED) secho(str(primary_key), fg=colors.YELLOW) secho("Public key, to be saved in server", fg=colors.BLUE) secho(primary_key.fingerprint, fg=colors.RED) secho(str(primary_key.pubkey), fg=colors.GREEN)
def test_encrypt_message_select_uid(self): # generate a temporary key with two UIDs, then encrypt a message u1 = PGPUID.new('UID One') u2 = PGPUID.new('UID Two') k = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) flags = {KeyFlags.Certify, KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage} k.add_uid(u1, usage=flags, hashes=[HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.AES128]) k.add_uid(u2, usage=flags, hashes=[HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.Camellia128]) emsg = k.pubkey.encrypt(PGPMessage.new('This message is about to be encrypted'), user='******') # assert that it was encrypted with Camellia128 and that we can decrypt it normally assert emsg._sessionkeys[0].decrypt_sk(k._key)[0] == SymmetricKeyAlgorithm.Camellia128 assert k.decrypt(emsg).message == 'This message is about to be encrypted'
def test_new_subkey(self, key_alg): key = self.gen_keys[key_alg] subkey = PGPKey.new(subkey_alg[key_alg], key_alg_size[subkey_alg[key_alg]]) assert subkey._key assert not isinstance(subkey._key, PrivSubKeyV4) # now add the subkey to key and then verify it key.add_subkey(subkey, usage={KeyFlags.EncryptCommunications}) # subkey should be a PrivSubKeyV4 now, not a PrivKeyV4 assert isinstance(subkey._key, PrivSubKeyV4) # self-verify sv = self.gen_keys[key_alg].verify(self.gen_keys[key_alg]) assert sv assert subkey in sv
def test_sign_security_txt__render(self) -> None: """Test templatetag rendering result.""" expected = """ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 -----BEGIN PGP SIGNATURE----- """ template: Template = Template( "{% load security_txt_tags %}" # noqa: FS003 "{% with security_txt as DATA %}{% sign_security_txt DATA %}{% endwith %}" # noqa: FS003,E501 ) key = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096) uid = PGPUID.new(pn="TEST", comment="Test", email="*****@*****.**") key.add_uid( uid, usage={ KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage, }, hashes=[ HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512, HashAlgorithm.SHA224, ], ciphers=[ SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES128, ], compression=[ CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP, CompressionAlgorithm.Uncompressed, ], ) Path(self.KEY_PATH).write_text(data=str(key)) result: str = template.render(context=Context()) self.assertTrue(expr=expected.strip() in result.strip())
def test_gen_key(self, alg, size): # create a primary key with a UID uid = PGPUID.new('Test Key', '{}.{}'.format(alg.name, size), '*****@*****.**') key = PGPKey.new(alg, size) if alg is PubKeyAlgorithm.ECDSA: # ECDSA keys require larger hash digests key.add_uid(uid, hashes=[HashAlgorithm.SHA384]) else: key.add_uid(uid, hashes=[HashAlgorithm.SHA224]) assert uid in key # self-verify the key assert key.verify(key) self.keys[(alg, size)] = key # try to verify with GPG self.gpg_verify_key(key)
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 generate_pgp_pair(self, comment, passphrase, armor=True, active=False): """Generate PGP key pair to be used by keyserver.""" # We need to specify all of our preferences because PGPy doesn't have any built-in key preference defaults at this time. # This example is similar to GnuPG 2.1.x defaults, with no expiration or preferred keyserver comment = comment if comment else "Generated for use in LocalEGA." key = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096) uid = PGPUID.new(self.name, email=self.email, comment=comment) key.add_uid( uid, usage={ KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage }, hashes=[ HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512, HashAlgorithm.SHA224 ], ciphers=[ SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES128 ], compression=[ CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP, CompressionAlgorithm.Uncompressed, ], ) # Protecting the key key.protect(passphrase, SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256) pub_data = str(key.pubkey) if armor else bytes( key.pubkey) # armored or not sec_data = str(key) if armor else bytes(key) # armored or not return (pub_data, sec_data)
def temp_subkey(): return PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512)
def test_new_key_invalid_size(self, badkey): key_alg, key_size = badkey with pytest.raises(ValueError): PGPKey.new(key_alg, key_size)
def test_new_key_no_uid_action(self): key = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 1024) with pytest.raises(PGPError): key.sign('asdf')
def test_new_key_unimplemented_alg(self, key_alg_unim): with pytest.raises(NotImplementedError): PGPKey.new(key_alg_unim, 512)