Skip to content

Commit

Permalink
Add encrypt/decrypt and sign/verify roundtrips
Browse files Browse the repository at this point in the history
This uses cached key generation, and ensures that we cover versions 4
and 6 of keys, as well as all the pubkey algorithms, and different
possible feature sets (SEIPDv1 and SEIPDv2).
  • Loading branch information
dkg committed Aug 10, 2023
1 parent 1c1eabe commit 55ed5df
Showing 1 changed file with 89 additions and 0 deletions.
89 changes: 89 additions & 0 deletions tests/test_13_version_and_pubkey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# coding=utf-8
""" Testing different versions of public keys across different versions of packets
"""

from typing import Dict, NamedTuple, Optional, Tuple

import pytest

from warnings import warn

from itertools import product
from datetime import datetime, timezone

from pgpy import PGPKey, PGPSignature, PGPMessage, PGPUID
from pgpy.constants import PubKeyAlgorithm, KeyFlags, HashAlgorithm, SymmetricKeyAlgorithm, CompressionAlgorithm, Features
from pgpy.errors import PGPDecryptionError


class KeyDescriptor(NamedTuple):
primary_alg: PubKeyAlgorithm
subkey_alg: PubKeyAlgorithm
key_version: int
features: Features

@property
def key_and_cert(self) -> Tuple[PGPKey, PGPKey]:
'cache the created keys to be able to reuse them cleanly'
if self not in kd_instances:
if (self.primary_alg, self.key_version) not in kd_primary_keys:
kd_primary_keys[(self.primary_alg, self.key_version)] = PGPKey.new(self.primary_alg, version=self.key_version, created=creation_time)
key = kd_primary_keys[(self.primary_alg, self.key_version)]
prefs = {
'usage': KeyFlags.Certify | KeyFlags.Sign,
'hashes': [
HashAlgorithm.SHA3_512,
HashAlgorithm.SHA3_256,
HashAlgorithm.SHA512,
HashAlgorithm.SHA256
],
'ciphers': [SymmetricKeyAlgorithm.AES256,
SymmetricKeyAlgorithm.AES128],
'compression': [CompressionAlgorithm.Uncompressed],
'features': self.features,
}
key |= key.certify(key, **prefs)
if self.key_version == 4:
key.add_uid(PGPUID.new('Example User <user@example.org>'), selfsign=True, **prefs)
if (self.subkey_alg, self.key_version) not in kd_subkeys:
kd_subkeys[(self.subkey_alg, self.key_version)] = PGPKey.new(self.subkey_alg, version=self.key_version, created=creation_time)
key.add_subkey(kd_subkeys[(self.subkey_alg, self.key_version)],
usage=KeyFlags.EncryptCommunications | KeyFlags.EncryptStorage)
cert = key.pubkey
kd_instances[self] = (key, cert)
return kd_instances[self]

def __repr__(self) -> str:
return f"v{self.key_version} {self.primary_alg.name},{self.subkey_alg.name} {self.features!r}"

kdescs = list(KeyDescriptor(*x) for x in product(list(filter(lambda x: x.can_sign and x.can_gen, PubKeyAlgorithm)),
list(filter(lambda x: x.can_encrypt and x.can_gen, PubKeyAlgorithm)),
[4,6],
[Features.SEIPDv1, Features.SEIPDv1 | Features.SEIPDv2]
))

creation_time = datetime.now(tz=timezone.utc)

kd_primary_keys: Dict[Tuple[PubKeyAlgorithm, int], PGPKey] = {}
kd_subkeys: Dict[Tuple[PubKeyAlgorithm, int], PGPKey] = {}
kd_instances: Dict[KeyDescriptor, Tuple[PGPKey, PGPKey]] = {}

class TestPGP_Version_Pubkey(object):
@pytest.mark.parametrize('kdesc', kdescs, ids=list(map(repr, kdescs)))
def test_encrypt_decrypt_roundtrip(self, kdesc: KeyDescriptor) -> None:
key, cert = kdesc.key_and_cert
msg = PGPMessage.new('this is a test', compression=CompressionAlgorithm.Uncompressed)

encmsg = cert.encrypt(msg)
encmsg2 = PGPMessage.from_blob(bytes(encmsg))
newmsg = key.decrypt(encmsg2)
assert newmsg.message == msg.message

@pytest.mark.parametrize('kdesc', kdescs, ids=list(map(repr, kdescs)))
def test_sign_verify_roundtrip(self, kdesc: KeyDescriptor) -> None:
key, cert = kdesc.key_and_cert

msg = 'this is a test'
sig = key.sign(msg)
sig2 = PGPSignature.from_blob(bytes(sig))
assert cert.verify(msg, sig2)

0 comments on commit 55ed5df

Please sign in to comment.