Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support for algorithms that have different input keysize requirement #324

Merged
merged 3 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ testlong: export JWCRYPTO_TESTS_ENABLE_MMA=True
testlong: export TOX_TESTENV_PASSENV=JWCRYPTO_TESTS_ENABLE_MMA
testlong:
rm -f .coverage
tox -e py36
tox -e py310

test:
rm -f .coverage
tox -e py36 --skip-missing-interpreter
tox -e py37 --skip-missing-interpreter
tox -e py38 --skip-missing-interpreter
tox -e py39 --skip-missing-interpreter
tox -e py310 --skip-missing-interpreter

DOCS_DIR = docs
.PHONY: docs
Expand Down
24 changes: 19 additions & 5 deletions jwcrypto/jwa.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def description(self):
@property
@abstractmethod
def keysize(self):
"""The actual/recommended/minimum key size"""
"""The algorithm key size"""

@property
@abstractmethod
Expand All @@ -56,6 +56,14 @@ def algorithm_usage_location(self):
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
Expand Down Expand Up @@ -894,12 +902,15 @@ def encrypt(self, k, a, m):
""" 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):]

Expand All @@ -920,14 +931,17 @@ def encrypt(self, k, a, m):
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
:param t: Authentication Tag

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):]

Expand Down Expand Up @@ -993,7 +1007,7 @@ def encrypt(self, k, a, m):
""" 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

Expand All @@ -1011,7 +1025,7 @@ def encrypt(self, k, a, m):
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
Expand Down
2 changes: 1 addition & 1 deletion jwcrypto/jwk.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ def _get_gen_size(self, params, default_size=None):
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):
Expand Down
9 changes: 9 additions & 0 deletions jwcrypto/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,15 @@ def test_generate_oct_key(self):
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')
Expand Down