Skip to content

Commit

Permalink
Add to_jwk to Ed25519Algorithm. (#642) (#643)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
JohannesWill and pre-commit-ci[bot] committed Apr 28, 2021
1 parent 7f6a236 commit 545931d
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Expand Up @@ -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>`__
--------------------------------------------------------------------
Expand Down
43 changes: 43 additions & 0 deletions jwt/algorithms.py
Expand Up @@ -37,6 +37,10 @@
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,
Expand Down Expand Up @@ -589,6 +593,45 @@ def verify(self, msg, key, sig):
except cryptography.exceptions.InvalidSignature:
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:
Expand Down
25 changes: 25 additions & 0 deletions tests/test_algorithms.py
Expand Up @@ -807,3 +807,28 @@ def test_ed25519_jwk_fails_on_invalid_json(self):
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"})

0 comments on commit 545931d

Please sign in to comment.