From ba04c1119e845259911a5df3946058293ccf1009 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Wed, 22 Feb 2023 16:14:16 -0500 Subject: [PATCH 1/2] Avoid spurious CryptographyDeprecationWarning If someone actually wants to use IDEA, CAST5, or Blowfish, we want to see the CryptographyDeprecationWarning objects emitted by cryptography.hazmat.primitives.ciphers. But if we're just looking up a non-deprecated cipher we should just return it directly. This avoids the following kinds of warnings: pgpy/pgpy/constants.py:191: CryptographyDeprecationWarning: IDEA has been deprecated bs = {SymmetricKeyAlgorithm.IDEA: algorithms.IDEA, pgpy/pgpy/constants.py:193: CryptographyDeprecationWarning: CAST5 has been deprecated SymmetricKeyAlgorithm.CAST5: algorithms.CAST5, pgpy/pgpy/constants.py:194: CryptographyDeprecationWarning: Blowfish has been deprecated SymmetricKeyAlgorithm.Blowfish: algorithms.Blowfish, --- pgpy/constants.py | 54 +++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/pgpy/constants.py b/pgpy/constants.py index 28a4561a..25707378 100644 --- a/pgpy/constants.py +++ b/pgpy/constants.py @@ -17,6 +17,7 @@ from cryptography.hazmat.backends import openssl from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.ciphers import algorithms +from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm from .types import FlagEnum from .decorators import classproperty @@ -187,28 +188,33 @@ class SymmetricKeyAlgorithm(IntEnum): #: Camellia with 256-bit key Camellia256 = 0x0D - @property - def cipher(self): - bs = {SymmetricKeyAlgorithm.IDEA: algorithms.IDEA, - SymmetricKeyAlgorithm.TripleDES: algorithms.TripleDES, - SymmetricKeyAlgorithm.CAST5: algorithms.CAST5, - SymmetricKeyAlgorithm.Blowfish: algorithms.Blowfish, - SymmetricKeyAlgorithm.AES128: algorithms.AES, - SymmetricKeyAlgorithm.AES192: algorithms.AES, - SymmetricKeyAlgorithm.AES256: algorithms.AES, - SymmetricKeyAlgorithm.Twofish256: namedtuple('Twofish256', ['block_size'])(block_size=128), - SymmetricKeyAlgorithm.Camellia128: algorithms.Camellia, - SymmetricKeyAlgorithm.Camellia192: algorithms.Camellia, - SymmetricKeyAlgorithm.Camellia256: algorithms.Camellia} - - if self in bs: - return bs[self] - + def cipher(self, key: bytes) -> CipherAlgorithm: + if self is SymmetricKeyAlgorithm.IDEA: + return algorithms.IDEA(key) + elif self is SymmetricKeyAlgorithm.TripleDES: + return algorithms.TripleDES(key) + elif self is SymmetricKeyAlgorithm.CAST5: + return algorithms.CAST5(key) + elif self is SymmetricKeyAlgorithm.Blowfish: + return algorithms.Blowfish(key) + elif self in {SymmetricKeyAlgorithm.AES128, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES256}: + return algorithms.AES(key) + elif self in {SymmetricKeyAlgorithm.Camellia128, SymmetricKeyAlgorithm.Camellia192, SymmetricKeyAlgorithm.Camellia256}: + return algorithms.Camellia(key) raise NotImplementedError(repr(self)) @property - def is_supported(self): - return callable(self.cipher) + def is_supported(self) -> bool: + return self in {SymmetricKeyAlgorithm.IDEA, + SymmetricKeyAlgorithm.TripleDES, + SymmetricKeyAlgorithm.CAST5, + SymmetricKeyAlgorithm.Blowfish, + SymmetricKeyAlgorithm.AES128, + SymmetricKeyAlgorithm.AES192, + SymmetricKeyAlgorithm.AES256, + SymmetricKeyAlgorithm.Camellia128, + SymmetricKeyAlgorithm.Camellia192, + SymmetricKeyAlgorithm.Camellia256} @property def is_insecure(self): @@ -216,8 +222,14 @@ def is_insecure(self): return self in insecure_ciphers @property - def block_size(self): - return self.cipher.block_size + def block_size(self) -> int: + if self in {SymmetricKeyAlgorithm.IDEA, + SymmetricKeyAlgorithm.TripleDES, + SymmetricKeyAlgorithm.CAST5, + SymmetricKeyAlgorithm.Blowfish}: + return 64 + else: + return 128 @property def key_size(self): From fb885e672c2adc2616f403808a1e53b542f9d151 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 27 Mar 2023 19:03:10 +0900 Subject: [PATCH 2/2] Fix test: ensure that deprecation warnings don't interfere with test suite Once CAST5 is deprecated, a deprecation warning might arise in addition to the warnings about already-protected secret keys might not be the first warning. Instead, we have the test look through the warnings and validate the content of any matching warning. --- tests/test_10_exceptions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_10_exceptions.py b/tests/test_10_exceptions.py index 299f3456..45e89ea5 100644 --- a/tests/test_10_exceptions.py +++ b/tests/test_10_exceptions.py @@ -172,10 +172,10 @@ def test_protect_pubkey(self, rsa_pub, recwarn): def test_protect_protected_key(self, rsa_enc, recwarn): rsa_enc.protect('QwertyUiop', SymmetricKeyAlgorithm.CAST5, HashAlgorithm.SHA1) - w = recwarn.pop(UserWarning) - assert str(w.message) == "This key is already protected with a passphrase - " \ - "please unlock it before attempting to specify a new passphrase" - assert w.filename == __file__ + warning = "This key is already protected with a passphrase - please unlock it before attempting to specify a new passphrase" + msgs = list(filter(lambda x: str(x.message) == warning, recwarn)) + assert len(msgs) == 1 + assert msgs[0].filename == __file__ def test_unlock_wrong_passphrase(self, rsa_enc): with pytest.raises(PGPDecryptionError):