Skip to content

Commit b0b0d66

Browse files
committed
add support for X448 and X25519
1 parent ef2b23b commit b0b0d66

File tree

2 files changed

+90
-42
lines changed

2 files changed

+90
-42
lines changed

src/cryptojwt/jwk/okp.py

Lines changed: 76 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,67 @@
33
from cryptography.hazmat.primitives import serialization
44
from cryptography.hazmat.primitives.asymmetric import ed448
55
from cryptography.hazmat.primitives.asymmetric import ed25519
6+
from cryptography.hazmat.primitives.asymmetric import x448
7+
from cryptography.hazmat.primitives.asymmetric import x25519
68

79
from cryptojwt.exception import KeyNotFound
810

911
from ..exception import DeSerializationNotPossible
1012
from ..exception import JWKESTException
1113
from ..exception import UnsupportedOKPCurve
12-
from ..utils import as_unicode
1314
from ..utils import b64d
1415
from ..utils import b64e
1516
from .asym import AsymmetricKey
1617
from .x509 import import_private_key_from_pem_file
1718
from .x509 import import_public_key_from_pem_data
1819
from .x509 import import_public_key_from_pem_file
1920

20-
OKPPublicKey = Union[ed25519.Ed25519PublicKey, ed448.Ed448PublicKey]
21-
OKPPrivateKey = Union[ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey]
21+
OKPPublicKey = Union[
22+
ed25519.Ed25519PublicKey, ed448.Ed448PublicKey, x25519.X25519PublicKey, x448.X448PublicKey
23+
]
24+
OKPPrivateKey = Union[
25+
ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey, x25519.X25519PrivateKey, x448.X448PrivateKey
26+
]
2227

23-
CRV2PUBLIC = {"Ed25519": ed25519.Ed25519PublicKey, "Ed448": ed448.Ed448PublicKey}
28+
CRV2PUBLIC = {
29+
"Ed25519": ed25519.Ed25519PublicKey,
30+
"Ed448": ed448.Ed448PublicKey,
31+
"X25519": x25519.X25519PublicKey,
32+
"X448": x448.X448PublicKey,
33+
}
2434

25-
CRV2PRIVATE = {"Ed25519": ed25519.Ed25519PrivateKey, "Ed448": ed448.Ed448PrivateKey}
35+
CRV2PRIVATE = {
36+
"Ed25519": ed25519.Ed25519PrivateKey,
37+
"Ed448": ed448.Ed448PrivateKey,
38+
"X25519": x25519.X25519PrivateKey,
39+
"X448": x448.X448PrivateKey,
40+
}
41+
42+
CRV_SIGN = ["Ed25519", "Ed448"]
43+
CRV_ENCR = ["X25519", "X448"]
2644

2745

2846
def is_private_key(key) -> bool:
29-
if isinstance(key, (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)):
47+
if isinstance(
48+
key,
49+
(
50+
ed25519.Ed25519PrivateKey,
51+
ed448.Ed448PrivateKey,
52+
x25519.X25519PrivateKey,
53+
x448.X448PrivateKey,
54+
),
55+
):
3056
return True
31-
elif isinstance(key, (ed25519.Ed25519PublicKey, ed448.Ed448PublicKey)):
57+
elif isinstance(
58+
key,
59+
(
60+
ed25519.Ed25519PublicKey,
61+
ed448.Ed448PublicKey,
62+
ed448.Ed448PublicKey,
63+
x25519.X25519PublicKey,
64+
x448.X448PublicKey,
65+
),
66+
):
3267
return False
3368
raise TypeError
3469

@@ -119,51 +154,50 @@ def deserialize(self):
119154
try:
120155
self.pub_key = CRV2PUBLIC[self.crv].from_public_bytes(_x)
121156
except KeyError:
122-
raise UnsupportedOKPCurve("Unsupported OKP curve: {}".format(num["crv"]))
157+
raise UnsupportedOKPCurve("Unsupported OKP curve: {}".format(self.crv))
158+
159+
def _serialize_public(self, key):
160+
self.x = b64e(
161+
key.public_bytes(
162+
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
163+
)
164+
).decode("ascii")
165+
166+
def _serialize_private(self, key):
167+
self._serialize_public(key.public_key())
168+
self.d = b64e(
169+
key.private_bytes(
170+
encoding=serialization.Encoding.Raw,
171+
format=serialization.PrivateFormat.Raw,
172+
encryption_algorithm=serialization.NoEncryption(),
173+
)
174+
).decode("ascii")
123175

124176
def _serialize(self, key):
125177
if isinstance(key, ed25519.Ed25519PublicKey):
126-
self.x = b64e(
127-
key.public_bytes(
128-
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
129-
)
130-
).decode("ascii")
178+
self._serialize_public(key)
131179
self.crv = "Ed25519"
132180
elif isinstance(key, ed25519.Ed25519PrivateKey):
133-
self.x = b64e(
134-
key.public_key().public_bytes(
135-
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
136-
)
137-
).decode("ascii")
138-
self.d = b64e(
139-
key.private_bytes(
140-
encoding=serialization.Encoding.Raw,
141-
format=serialization.PrivateFormat.Raw,
142-
encryption_algorithm=serialization.NoEncryption(),
143-
)
144-
).decode("ascii")
181+
self._serialize_private(key)
145182
self.crv = "Ed25519"
183+
elif isinstance(key, x25519.X25519PublicKey):
184+
self._serialize_public(key)
185+
self.crv = "X25519"
186+
elif isinstance(key, x25519.X25519PrivateKey):
187+
self._serialize_private(key)
188+
self.crv = "X25519"
146189
elif isinstance(key, ed448.Ed448PublicKey):
147-
self.x = b64e(
148-
key.public_bytes(
149-
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
150-
)
151-
).decode("ascii")
190+
self._serialize_public(key)
152191
self.crv = "Ed448"
153192
elif isinstance(key, ed448.Ed448PrivateKey):
154-
self.x = b64e(
155-
key.public_key().public_bytes(
156-
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
157-
)
158-
).decode("ascii")
159-
self.d = b64e(
160-
key.private_bytes(
161-
encoding=serialization.Encoding.Raw,
162-
format=serialization.PrivateFormat.Raw,
163-
encryption_algorithm=serialization.NoEncryption(),
164-
)
165-
).decode("ascii")
193+
self._serialize_private(key)
166194
self.crv = "Ed448"
195+
elif isinstance(key, x448.X448PublicKey):
196+
self._serialize_public(key)
197+
self.crv = "X448"
198+
elif isinstance(key, x448.X448PrivateKey):
199+
self._serialize_private(key)
200+
self.crv = "X448"
167201

168202
def serialize(self, private=False):
169203
"""

tests/test_02_jwk.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from cryptography.hazmat.primitives.asymmetric import ed448
1313
from cryptography.hazmat.primitives.asymmetric import ed25519
1414
from cryptography.hazmat.primitives.asymmetric import rsa
15+
from cryptography.hazmat.primitives.asymmetric import x448
16+
from cryptography.hazmat.primitives.asymmetric import x25519
1517

1618
from cryptojwt.exception import DeSerializationNotPossible
1719
from cryptojwt.exception import UnsupportedAlgorithm
@@ -743,6 +745,18 @@ def test_new_okp_key():
743745
assert isinstance(okp_key, OKPKey)
744746
assert okp_key.crv == "Ed25519"
745747

748+
okp_key = new_okp_key("Ed448")
749+
assert isinstance(okp_key, OKPKey)
750+
assert okp_key.crv == "Ed448"
751+
752+
okp_key = new_okp_key("X25519")
753+
assert isinstance(okp_key, OKPKey)
754+
assert okp_key.crv == "X25519"
755+
756+
okp_key = new_okp_key("X448")
757+
assert isinstance(okp_key, OKPKey)
758+
assert okp_key.crv == "X448"
759+
746760

747761
def test_create_okp_key():
748762
okp = new_okp_key("Ed25519")

0 commit comments

Comments
 (0)