diff options
author | JohannesWill <johannes.will@siemens.com> | 2021-04-28 13:42:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-28 07:42:22 -0400 |
commit | 545931dafd9ec318e8d8acff6d5a4daeedf50863 (patch) | |
tree | 75e4217b59ba46ecf8e6a18ffde584ecb1731d91 | |
parent | 7f6a2361943ffae20007eb014900060c6b21d9cc (diff) | |
download | pyjwt-545931dafd9ec318e8d8acff6d5a4daeedf50863.tar.gz |
Add to_jwk to Ed25519Algorithm. (#642) (#643)
* Add to_jwk to Ed25519Algorithm. (#642)
* add test for invalid key
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* update CHANGELOG for #643
* remove alg from jwk
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
-rw-r--r-- | CHANGELOG.rst | 1 | ||||
-rw-r--r-- | jwt/algorithms.py | 43 | ||||
-rw-r--r-- | tests/test_algorithms.py | 25 |
3 files changed, 69 insertions, 0 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9fb832f..624b676 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -27,6 +27,7 @@ Added - Add missing exceptions.InvalidKeyError to jwt module __init__ imports `#620 <https://github.com/jpadilla/pyjwt/pull/620>`__ - Add support for ES256K algorithm `#629 <https://github.com/jpadilla/pyjwt/pull/629>`__ - Add `from_jwk()` to Ed25519Algorithm `#621 <https://github.com/jpadilla/pyjwt/pull/621>`__ +- Add `to_jwk()` to Ed25519Algorithm `#643 <https://github.com/jpadilla/pyjwt/pull/643>`__ `v2.0.1 <https://github.com/jpadilla/pyjwt/compare/2.0.0...2.0.1>`__ -------------------------------------------------------------------- diff --git a/jwt/algorithms.py b/jwt/algorithms.py index bed4033..cee66a4 100644 --- a/jwt/algorithms.py +++ b/jwt/algorithms.py @@ -37,6 +37,10 @@ try: rsa_recover_prime_factors, ) from cryptography.hazmat.primitives.serialization import ( + Encoding, + NoEncryption, + PrivateFormat, + PublicFormat, load_pem_private_key, load_pem_public_key, load_ssh_public_key, @@ -590,6 +594,45 @@ if has_crypto: return False @staticmethod + def to_jwk(key): + if isinstance(key, Ed25519PublicKey): + x = key.public_bytes( + encoding=Encoding.Raw, + format=PublicFormat.Raw, + ) + + return json.dumps( + { + "x": base64url_encode(force_bytes(x)).decode(), + "kty": "OKP", + "crv": "Ed25519", + } + ) + + if isinstance(key, Ed25519PrivateKey): + d = key.private_bytes( + encoding=Encoding.Raw, + format=PrivateFormat.Raw, + encryption_algorithm=NoEncryption(), + ) + + x = key.public_key().public_bytes( + encoding=Encoding.Raw, + format=PublicFormat.Raw, + ) + + return json.dumps( + { + "x": base64url_encode(force_bytes(x)).decode(), + "d": base64url_encode(force_bytes(d)).decode(), + "kty": "OKP", + "crv": "Ed25519", + } + ) + + raise InvalidKeyError("Not a public or private key") + + @staticmethod def from_jwk(jwk): try: if isinstance(jwk, str): diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py index 982a145..417f91d 100644 --- a/tests/test_algorithms.py +++ b/tests/test_algorithms.py @@ -807,3 +807,28 @@ class TestEd25519Algorithms: v["d"] = "123" with pytest.raises(InvalidKeyError): algo.from_jwk(v) + + def test_ed25519_to_jwk_works_with_from_jwk(self): + algo = Ed25519Algorithm() + + with open(key_path("jwk_okp_key_Ed25519.json")) as keyfile: + priv_key_1 = algo.from_jwk(keyfile.read()) + + with open(key_path("jwk_okp_pub_Ed25519.json")) as keyfile: + pub_key_1 = algo.from_jwk(keyfile.read()) + + pub = algo.to_jwk(pub_key_1) + pub_key_2 = algo.from_jwk(pub) + pri = algo.to_jwk(priv_key_1) + priv_key_2 = algo.from_jwk(pri) + + signature_1 = algo.sign(b"Hello World!", priv_key_1) + signature_2 = algo.sign(b"Hello World!", priv_key_2) + assert algo.verify(b"Hello World!", pub_key_2, signature_1) + assert algo.verify(b"Hello World!", pub_key_2, signature_2) + + def test_ed25519_to_jwk_raises_exception_on_invalid_key(self): + algo = Ed25519Algorithm() + + with pytest.raises(InvalidKeyError): + algo.to_jwk({"not": "a valid key"}) |