Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-jwcrypto for openSUSE:Factory checked in at 2023-12-09 22:49:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-jwcrypto (Old) and /work/SRC/openSUSE:Factory/.python-jwcrypto.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jwcrypto" Sat Dec 9 22:49:00 2023 rev:14 rq:1131710 version:1.5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-jwcrypto/python-jwcrypto.changes 2022-11-20 19:46:52.949192210 +0100 +++ /work/SRC/openSUSE:Factory/.python-jwcrypto.new.25432/python-jwcrypto.changes 2023-12-09 22:49:00.722326431 +0100 @@ -1,0 +2,14 @@ +Thu Dec 7 22:03:04 UTC 2023 - Dirk Müller <dmuel...@suse.com> + +- update to 1.5.0: + * Minor bugfixes and the addition of Brainpool curves. + * Raising the bar for minimum pyca/cryptography + * Fix typos with codespell + * Add codespell checks in CI + * Add Brainpool EC-curves support + * Fix error message + * Fix assorted CI issue + * Better support for algorithms that have different input + keysize requirement + +------------------------------------------------------------------- Old: ---- jwcrypto-1.4.2.tar.gz New: ---- jwcrypto-1.5.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-jwcrypto.spec ++++++ --- /var/tmp/diff_new_pack.ib3z8l/_old 2023-12-09 22:49:01.362349538 +0100 +++ /var/tmp/diff_new_pack.ib3z8l/_new 2023-12-09 22:49:01.366349682 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-jwcrypto # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -21,20 +21,20 @@ %define skip_python2 1 Name: python-jwcrypto -Version: 1.4.2 +Version: 1.5.0 Release: 0 Summary: Python module package implementing JOSE Web standards License: LGPL-3.0-only URL: https://github.com/latchset/jwcrypto Source: https://files.pythonhosted.org/packages/source/j/jwcrypto/jwcrypto-%{version}.tar.gz BuildRequires: %{python_module Deprecated} -BuildRequires: %{python_module cryptography >= 2.3} +BuildRequires: %{python_module cryptography >= 3.4} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-Deprecated -Requires: python-cryptography >= 2.3 +Requires: python-cryptography >= 3.4 BuildArch: noarch %python_subpackages ++++++ jwcrypto-1.4.2.tar.gz -> jwcrypto-1.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/PKG-INFO new/jwcrypto-1.5.0/PKG-INFO --- old/jwcrypto-1.4.2/PKG-INFO 2022-09-15 15:01:52.656641000 +0200 +++ new/jwcrypto-1.5.0/PKG-INFO 2023-05-30 19:45:13.820392600 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: jwcrypto -Version: 1.4.2 +Version: 1.5.0 Summary: Implementation of JOSE Web standards Home-page: https://github.com/latchset/jwcrypto Maintainer: JWCrypto Project Contributors diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto/VERSION new/jwcrypto-1.5.0/jwcrypto/VERSION --- old/jwcrypto-1.4.2/jwcrypto/VERSION 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto/VERSION 2023-05-30 19:44:53.000000000 +0200 @@ -1 +1 @@ -1.4.2 +1.5.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto/jwa.py new/jwcrypto-1.5.0/jwcrypto/jwa.py --- old/jwcrypto-1.4.2/jwcrypto/jwa.py 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto/jwa.py 2023-05-30 19:44:53.000000000 +0200 @@ -44,7 +44,7 @@ @property @abstractmethod def keysize(self): - """The actual/recommended/minimum key size""" + """The algorithm key size""" @property @abstractmethod @@ -56,6 +56,14 @@ def algorithm_use(self): """One of 'sig', 'kex', 'enc'""" + @property + def input_keysize(self): + """The input key size""" + try: + return self.wrap_key_size + except AttributeError: + return self.keysize + def _bitsize(x): return len(x) * 8 @@ -395,7 +403,7 @@ cek = super(_Rsa15, self).unwrap(key, bitsize, ek, headers) # always raise so we always run through the exception handling # code in all cases - raise Exception('Dummy') + raise ValueError('Dummy') except Exception: # pylint: disable=broad-except return cek @@ -894,12 +902,15 @@ """ Encrypt according to the selected encryption and hashing functions. - :param k: Encryption key (optional) + :param k: Encryption key :param a: Additional Authentication Data :param m: Plaintext Returns a dictionary with the computed data. """ + if len(k) != _inbytes(self.wrap_key_size): + raise ValueError("Invalid input key size") + hkey = k[:_inbytes(self.keysize)] ekey = k[_inbytes(self.keysize):] @@ -920,7 +931,7 @@ def decrypt(self, k, a, iv, e, t): """ Decrypt according to the selected encryption and hashing functions. - :param k: Encryption key (optional) + :param k: Encryption key :param a: Additional Authenticated Data :param iv: Initialization Vector :param e: Ciphertext @@ -928,6 +939,9 @@ Returns plaintext or raises an error """ + if len(k) != _inbytes(self.wrap_key_size): + raise ValueError("Invalid input key size") + hkey = k[:_inbytes(self.keysize)] dkey = k[_inbytes(self.keysize):] @@ -990,10 +1004,10 @@ # RFC 7518 - 5.3 def encrypt(self, k, a, m): - """ Encrypt accoriding to the selected encryption and hashing + """ Encrypt according to the selected encryption and hashing functions. - :param k: Encryption key (optional) + :param k: Encryption key :param a: Additional Authentication Data :param m: Plaintext @@ -1009,9 +1023,9 @@ return (iv, e, encryptor.tag) def decrypt(self, k, a, iv, e, t): - """ Decrypt accoriding to the selected encryption and hashing + """ Decrypt according to the selected encryption and hashing functions. - :param k: Encryption key (optional) + :param k: Encryption key :param a: Additional Authenticated Data :param iv: Initialization Vector :param e: Ciphertext @@ -1053,6 +1067,54 @@ algorithm_use = 'enc' +class _BP256R1(_RawEC, JWAAlgorithm): + + name = "BP256R1" + description = ( + "ECDSA using Brainpool256R1 curve and SHA-256" + " (unregistered, custom-defined in breach" + " of IETF rules by gematik GmbH)" + ) + keysize = 256 + algorithm_usage_location = 'alg' + algorithm_use = 'sig' + + def __init__(self): + super(_BP256R1, self).__init__('BP-256', hashes.SHA256()) + + +class _BP384R1(_RawEC, JWAAlgorithm): + + name = "BP384R1" + description = ( + "ECDSA using Brainpool384R1 curve and SHA-384" + " (unregistered, custom-defined in breach" + " of IETF rules by gematik GmbH)" + ) + keysize = 384 + algorithm_usage_location = 'alg' + algorithm_use = 'sig' + + def __init__(self): + super(_BP384R1, self).__init__('BP-384', hashes.SHA384()) + + +class _BP512R1(_RawEC, JWAAlgorithm): + + name = "BP512R1" + description = ( + "ECDSA using Brainpool512R1 curve and SHA-512" + " (unregistered, custom-defined in breach" + " of IETF rules by gematik GmbH)" + ) + keysize = 512 + algorithm_usage_location = 'alg' + algorithm_use = 'sig' + + def __init__(self): + super(_BP512R1, self).__init__('BP-512', hashes.SHA512()) + + class JWA: """JWA Signing Algorithms. @@ -1097,7 +1159,10 @@ 'A256CBC-HS512': _A256CbcHs512, 'A128GCM': _A128Gcm, 'A192GCM': _A192Gcm, - 'A256GCM': _A256Gcm + 'A256GCM': _A256Gcm, + 'BP256R1': _BP256R1, + 'BP384R1': _BP384R1, + 'BP512R1': _BP512R1 } @classmethod diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto/jwk.py new/jwcrypto-1.5.0/jwcrypto/jwk.py --- old/jwcrypto-1.4.2/jwcrypto/jwk.py 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto/jwk.py 2023-05-30 19:44:53.000000000 +0200 @@ -162,7 +162,17 @@ 'Ed25519': 'Ed25519 signature algorithm key pairs', 'Ed448': 'Ed448 signature algorithm key pairs', 'X25519': 'X25519 function key pairs', - 'X448': 'X448 function key pairs'} + 'X448': 'X448 function key pairs', + 'BP-256': 'BrainpoolP256R1 curve' + ' (unregistered, custom-defined in breach' + ' of IETF rules by gematik GmbH)', + 'BP-384': 'BrainpoolP384R1 curve' + ' (unregistered, custom-defined in breach' + ' of IETF rules by gematik GmbH)', + 'BP-512': 'BrainpoolP512R1 curve' + ' (unregistered, custom-defined in breach' + ' of IETF rules by gematik GmbH)' + } """Registry of allowed Elliptic Curves""" # RFC 7517 - 8.2 @@ -186,7 +196,10 @@ JWKpycaCurveMap = {'secp256r1': 'P-256', 'secp384r1': 'P-384', 'secp521r1': 'P-521', - 'secp256k1': 'secp256k1'} + 'secp256k1': 'secp256k1', + 'brainpoolP256r1': 'BP-256', + 'brainpoolP384r1': 'BP-384', + 'brainpoolP512r1': 'BP-512'} IANANamedInformationHashAlgorithmRegistry = { 'sha-256': hashes.SHA256(), @@ -317,7 +330,7 @@ valid key type as value then a new key will be generated according to the defaults or provided key strength options (type specific). - :param \**kwargs: parameters (otional). + :param \**kwargs: parameters (optional). :raises InvalidJWKType: if the key type is invalid :raises InvalidJWKValue: if incorrect or inconsistent parameters @@ -364,7 +377,7 @@ alg = JWA.instantiate_alg(params['alg']) except KeyError as e: raise ValueError("Invalid 'alg' parameter") from e - size = alg.keysize + size = alg.input_keysize return size def _generate_oct(self, params): @@ -453,6 +466,12 @@ return ec.SECP521R1() elif cname == 'secp256k1': return ec.SECP256K1() + elif cname == 'BP-256': + return ec.BrainpoolP256R1() + elif cname == 'BP-384': + return ec.BrainpoolP384R1() + elif cname == 'BP-512': + return ec.BrainpoolP512R1() elif cname in _OKP_CURVES_TABLE: return _OKP_CURVES_TABLE[cname] else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto/jws.py new/jwcrypto-1.5.0/jwcrypto/jws.py --- old/jwcrypto-1.4.2/jwcrypto/jws.py 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto/jws.py 2023-05-30 19:44:53.000000000 +0200 @@ -262,7 +262,7 @@ p = json_decode(protected) if not isinstance(p, dict): raise InvalidJWSSignature('Invalid Protected header') - # merge heders, and verify there are no duplicates + # merge headers, and verify there are no duplicates if header: if not isinstance(header, dict): raise InvalidJWSSignature('Invalid Unprotected header') @@ -324,7 +324,7 @@ return dp else: raise InvalidJWSOperation('Object Payload present but' - ' Deatched Payload provided') + ' Detached Payload provided') return op def verify(self, key, alg=None, detached_payload=None): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto/jwt.py new/jwcrypto-1.5.0/jwcrypto/jwt.py --- old/jwcrypto-1.4.2/jwcrypto/jwt.py 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto/jwt.py 2023-05-30 19:44:53.000000000 +0200 @@ -426,7 +426,8 @@ if name not in claims or claims[name] is None: return if not isinstance(claims[name], str): - raise JWTInvalidClaimFormat("Claim %s is not a StringOrURI type") + raise JWTInvalidClaimFormat( + "Claim %s is not a StringOrURI type" % (name, )) def _check_array_or_string_claim(self, name, claims): if name not in claims or claims[name] is None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto/tests-cookbook.py new/jwcrypto-1.5.0/jwcrypto/tests-cookbook.py --- old/jwcrypto-1.4.2/jwcrypto/tests-cookbook.py 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto/tests-cookbook.py 2023-05-30 19:44:53.000000000 +0200 @@ -1101,7 +1101,7 @@ # In general we can't compare ciphertexts with the reference because # either the algorithms use random nonces to authenticate the ciphertext -# or we randomly genrate the nonce when we create the JWe. +# or we randomly generate the nonce when we create the JWe. # To double check implementation we encrypt/decrypt our own input and then # decrypt the reference and check it against the given plaintext class Cookbook08JWETests(unittest.TestCase): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto/tests.py new/jwcrypto-1.5.0/jwcrypto/tests.py --- old/jwcrypto-1.4.2/jwcrypto/tests.py 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto/tests.py 2023-05-30 19:44:53.000000000 +0200 @@ -294,7 +294,66 @@ "x": "Ss6na3mcci8Ud4lQrjaB_T40sfKApEcl2RLIWOJdjow", "y": "7l9qIKtKPW6oEiOYBt7r22Sm0mtFJU-yBkkvMvpscd8", "d": "GYhU2vrYGZrjLZn71Xniqm54Mi53xiYtaTLawzaf9dA" + } + ] +} + +PublicKeys_brainpool = { + "keys": [ + { + "kty": "EC", + "crv": "BP-256", + "x": "mpkJ29_CYAD0mzQ_MsrbjFMFYtcc9Oxpro37Fa4cLfI", + "y": "iBfhNHk0cI73agNpjbKW62dvuVxn7kxp1Sm8oDnzHl8", + }, + { + "kty": "EC", + "crv": "BP-384", + "x": ("WZanneaC2Hi3xslA4znJv7otyEdV5dTPzNUvBjBXPM" + "ytf4mRY9JaAITdItjvUTAh"), + "y": ("KNLRTNdvUg66aB_TVW4POZkE3q8S0YoQrCzYUrExRDe" + "_BXikkqIama-GYQ3UBOQL"), + }, + { + "kty": "EC", + "crv": "BP-512", + "x": ("aQXpvz7DH9OK5eFNO9dY3BdPY1v0-8Rg9KC322PY1Jy" + "BJq3EhT0uR_-tgbL2E_aGP6k56lF1xIOOtQxo8zziGA"), + "y": ("l9XLHHncigOPr5Tvnj_mVzBFv6i7rdBQrLTq3RXZlCC" + "_f_q6L2o79K9IrN_J2wWxAfS8ekuGPGlHZUzK-3D9sA"), + } + ] +} + +PrivateKeys_brainpool = { + "keys": [ + { + "kty": "EC", + "crv": "BP-256", + "x": "mpkJ29_CYAD0mzQ_MsrbjFMFYtcc9Oxpro37Fa4cLfI", + "y": "iBfhNHk0cI73agNpjbKW62dvuVxn7kxp1Sm8oDnzHl8", + "d": "KdKRgq0WEM97BQw3jpW_fTOep6fn-Samv4DfDNb-4s4" + }, + { + "kty": "EC", + "crv": "BP-384", + "x": ("WZanneaC2Hi3xslA4znJv7otyEdV5dTPzNUvBjBXPM" + "ytf4mRY9JaAITdItjvUTAh"), + "y": ("KNLRTNdvUg66aB_TVW4POZkE3q8S0YoQrCzYUrExRDe" + "_BXikkqIama-GYQ3UBOQL"), + "d": ("B5WeRV0-RztAPAhRbphSAUrsIzy-eSfWGSM5FxOQGlJ" + "cq-ECLA_-SIlH7NdWIEJY") }, + { + "kty": "EC", + "crv": "BP-512", + "x": ("aQXpvz7DH9OK5eFNO9dY3BdPY1v0-8Rg9KC322PY1Jy" + "BJq3EhT0uR_-tgbL2E_aGP6k56lF1xIOOtQxo8zziGA"), + "y": ("l9XLHHncigOPr5Tvnj_mVzBFv6i7rdBQrLTq3RXZlCC" + "_f_q6L2o79K9IrN_J2wWxAfS8ekuGPGlHZUzK-3D9sA"), + "d": ("F_LJ9rebAjOtxoMUfngIywYsnJlZNjy3gxNAEvHjSkL" + "m6RUUdLXDwc50EMp0LeTh1ku039D5kldK3S9Xi0yKZA") + } ] } @@ -372,6 +431,15 @@ e.deserialize(enc, key) self.assertEqual(e.payload.decode('utf-8'), 'test') + # also test key generation with input_keysize != keysize + key = jwk.JWK.generate(kty='oct', alg="A128CBC-HS256") + self.assertEqual(len(base64url_decode(key['k'])), 32) + e = jwe.JWE('test', '{"alg":"A256KW","enc":"A128CBC-HS256"}') + e.add_recipient(key) + enc = e.serialize() + e.deserialize(enc, key) + self.assertEqual(e.payload.decode('utf-8'), 'test') + def test_generate_EC_key(self): # Backwards compat curve key = jwk.JWK.generate(kty='EC', curve='P-256') @@ -385,6 +453,15 @@ # New secp256k curve key = jwk.JWK.generate(kty='EC', curve='secp256k1') key.get_op_key('verify', 'secp256k1') + # Brainpool256R1 curve + key = jwk.JWK.generate(kty='EC', crv='BP-256') + key.get_op_key('verify', 'BP-256') + # Brainpool384R1 curve + key = jwk.JWK.generate(kty='EC', crv='BP-384') + key.get_op_key('verify', 'BP-384') + # Brainpool256R1 curve + key = jwk.JWK.generate(kty='EC', crv='BP-512') + key.get_op_key('verify', 'BP-512') def test_generate_OKP_keys(self): for crv in jwk.ImplementedOkpCurves: @@ -428,7 +505,7 @@ ks3 = jwk.JWKSet.from_json(ks.export()) self.assertEqual(len(ks), len(ks3)) - # Test key set with mutiple keys + # Test key set with multiple keys ksm = jwk.JWKSet.from_json(json_encode(PrivateKeys)) num = 0 for item in ksm: @@ -438,7 +515,7 @@ self.assertEqual(num, len(PrivateKeys['keys'])) def test_jwkset_get_keys(self): - # Test key set with mutiple keys + # Test key set with multiple keys ksm = jwk.JWKSet.from_json(json_encode(PrivateKeys)) k1 = jwk.JWK.from_json(json_encode(PrivateKeys['keys'][0])) kwargs = RSAPrivateKey.copy() @@ -576,6 +653,16 @@ for key in keylist: jwk.JWK(**key) + def test_create_pubKeys_brainpool(self): + keylist = PublicKeys_brainpool['keys'] + for key in keylist: + jwk.JWK(**key) + + def test_create_priKeys_brainpool(self): + keylist = PrivateKeys_brainpool['keys'] + for key in keylist: + jwk.JWK(**key) + def test_thumbprint_eddsa(self): for i in range(0, len(PublicKeys_EdDsa['keys'])): k = jwk.JWK(**PublicKeys_EdDsa['keys'][i]) @@ -881,7 +968,7 @@ self.assertEqual(decsig, test['signature']) else: # Check we can verify the test signature independently - # this is so taht we can test the ECDSA agaist a known + # this is so that we can test the ECDSA against a known # good signature s.verify(test['signature']) @@ -926,7 +1013,7 @@ def test_E(self): s = jws.JWS(A6_example['payload']) with self.assertRaises(jws.InvalidJWSSignature): - jws.InvalidJWSSignature(s.deserialize, E_negative) + s.deserialize(E_negative) s.verify(None) def test_customhdr_jws(self): @@ -987,6 +1074,31 @@ jws_verify.verify(key.public()) self.assertEqual(jws_verify.payload, payload) + def test_brainpool_signing_and_verification(self): + for key_data in PrivateKeys_brainpool['keys']: + key = jwk.JWK(**key_data) + payload = bytes(bytearray(A1_payload)) + jws_test = jws.JWS(payload) + + curve_name = key.get('crv') + if curve_name == "BP-256": + alg = "BP256R1" + elif curve_name == "BP-384": + alg = "BP384R1" + else: + alg = "BP512R1" + + jws_test.allowed_algs = [alg] + jws_test.add_signature(key, None, json_encode({"alg": alg}), None) + jws_test_serialization_compact = jws_test.serialize(compact=True) + + jws_verify = jws.JWS() + jws_verify.allowed_algs = [alg] + jws_verify.deserialize(jws_test_serialization_compact) + jws_verify.verify(key.public()) + + self.assertEqual(jws_verify.payload, payload) + def test_jws_issue_224(self): key = jwk.JWK().generate(kty='oct') @@ -1783,7 +1895,7 @@ token.make_encrypted_token(key) enctok = token.serialize() - # test workaroud for older applications + # test workaround for older applications jwt.JWT_expect_type = False jwt.JWT(jwt=enctok, key=key) jwt.JWT_expect_type = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto.egg-info/PKG-INFO new/jwcrypto-1.5.0/jwcrypto.egg-info/PKG-INFO --- old/jwcrypto-1.4.2/jwcrypto.egg-info/PKG-INFO 2022-09-15 15:01:52.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto.egg-info/PKG-INFO 2023-05-30 19:45:13.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: jwcrypto -Version: 1.4.2 +Version: 1.5.0 Summary: Implementation of JOSE Web standards Home-page: https://github.com/latchset/jwcrypto Maintainer: JWCrypto Project Contributors diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/jwcrypto.egg-info/requires.txt new/jwcrypto-1.5.0/jwcrypto.egg-info/requires.txt --- old/jwcrypto-1.4.2/jwcrypto.egg-info/requires.txt 2022-09-15 15:01:52.000000000 +0200 +++ new/jwcrypto-1.5.0/jwcrypto.egg-info/requires.txt 2023-05-30 19:45:13.000000000 +0200 @@ -1,2 +1,2 @@ -cryptography>=2.3 +cryptography>=3.4 deprecated diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/setup.py new/jwcrypto-1.5.0/setup.py --- old/jwcrypto-1.4.2/setup.py 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/setup.py 2023-05-30 19:44:53.000000000 +0200 @@ -37,7 +37,7 @@ ], data_files = [('share/doc/jwcrypto', ['LICENSE', 'README.md'])], install_requires = [ - 'cryptography >= 2.3', + 'cryptography >= 3.4', 'deprecated', ], python_requires = '>= 3.6', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jwcrypto-1.4.2/tox.ini new/jwcrypto-1.5.0/tox.ini --- old/jwcrypto-1.4.2/tox.ini 2022-09-15 15:01:22.000000000 +0200 +++ new/jwcrypto-1.5.0/tox.ini 2023-05-30 19:44:53.000000000 +0200 @@ -58,6 +58,13 @@ commands = sphinx-build -v -W -b doctest -d {envtmpdir}/doctrees . {envtmpdir}/doctest +[testenv:codespell] +basepython = python3.10 +deps = + codespell +commands = + codespell --ignore-words-list="ser,ect" jwcrypto + [pytest] python_files = jwcrypto/test*.py