1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import annotations
6
7import abc
8import typing
9
10from cryptography import utils
11from cryptography.hazmat._oid import ObjectIdentifier
12from cryptography.hazmat.bindings._rust import openssl as rust_openssl
13from cryptography.hazmat.primitives import _serialization, hashes
14from cryptography.hazmat.primitives.asymmetric import utils as asym_utils
15
16
17class EllipticCurveOID:
18 SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1")
19 SECP224R1 = ObjectIdentifier("1.3.132.0.33")
20 SECP256K1 = ObjectIdentifier("1.3.132.0.10")
21 SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7")
22 SECP384R1 = ObjectIdentifier("1.3.132.0.34")
23 SECP521R1 = ObjectIdentifier("1.3.132.0.35")
24 BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7")
25 BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11")
26 BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13")
27 SECT163K1 = ObjectIdentifier("1.3.132.0.1")
28 SECT163R2 = ObjectIdentifier("1.3.132.0.15")
29 SECT233K1 = ObjectIdentifier("1.3.132.0.26")
30 SECT233R1 = ObjectIdentifier("1.3.132.0.27")
31 SECT283K1 = ObjectIdentifier("1.3.132.0.16")
32 SECT283R1 = ObjectIdentifier("1.3.132.0.17")
33 SECT409K1 = ObjectIdentifier("1.3.132.0.36")
34 SECT409R1 = ObjectIdentifier("1.3.132.0.37")
35 SECT571K1 = ObjectIdentifier("1.3.132.0.38")
36 SECT571R1 = ObjectIdentifier("1.3.132.0.39")
37
38
39class EllipticCurve(metaclass=abc.ABCMeta):
40 @property
41 @abc.abstractmethod
42 def name(self) -> str:
43 """
44 The name of the curve. e.g. secp256r1.
45 """
46
47 @property
48 @abc.abstractmethod
49 def key_size(self) -> int:
50 """
51 Bit size of a secret scalar for the curve.
52 """
53
54
55class EllipticCurveSignatureAlgorithm(metaclass=abc.ABCMeta):
56 @property
57 @abc.abstractmethod
58 def algorithm(
59 self,
60 ) -> asym_utils.Prehashed | hashes.HashAlgorithm:
61 """
62 The digest algorithm used with this signature.
63 """
64
65
66class EllipticCurvePrivateKey(metaclass=abc.ABCMeta):
67 @abc.abstractmethod
68 def exchange(
69 self, algorithm: ECDH, peer_public_key: EllipticCurvePublicKey
70 ) -> bytes:
71 """
72 Performs a key exchange operation using the provided algorithm with the
73 provided peer's public key.
74 """
75
76 @abc.abstractmethod
77 def public_key(self) -> EllipticCurvePublicKey:
78 """
79 The EllipticCurvePublicKey for this private key.
80 """
81
82 @property
83 @abc.abstractmethod
84 def curve(self) -> EllipticCurve:
85 """
86 The EllipticCurve that this key is on.
87 """
88
89 @property
90 @abc.abstractmethod
91 def key_size(self) -> int:
92 """
93 Bit size of a secret scalar for the curve.
94 """
95
96 @abc.abstractmethod
97 def sign(
98 self,
99 data: bytes,
100 signature_algorithm: EllipticCurveSignatureAlgorithm,
101 ) -> bytes:
102 """
103 Signs the data
104 """
105
106 @abc.abstractmethod
107 def private_numbers(self) -> EllipticCurvePrivateNumbers:
108 """
109 Returns an EllipticCurvePrivateNumbers.
110 """
111
112 @abc.abstractmethod
113 def private_bytes(
114 self,
115 encoding: _serialization.Encoding,
116 format: _serialization.PrivateFormat,
117 encryption_algorithm: _serialization.KeySerializationEncryption,
118 ) -> bytes:
119 """
120 Returns the key serialized as bytes.
121 """
122
123
124EllipticCurvePrivateKeyWithSerialization = EllipticCurvePrivateKey
125EllipticCurvePrivateKey.register(rust_openssl.ec.ECPrivateKey)
126
127
128class EllipticCurvePublicKey(metaclass=abc.ABCMeta):
129 @property
130 @abc.abstractmethod
131 def curve(self) -> EllipticCurve:
132 """
133 The EllipticCurve that this key is on.
134 """
135
136 @property
137 @abc.abstractmethod
138 def key_size(self) -> int:
139 """
140 Bit size of a secret scalar for the curve.
141 """
142
143 @abc.abstractmethod
144 def public_numbers(self) -> EllipticCurvePublicNumbers:
145 """
146 Returns an EllipticCurvePublicNumbers.
147 """
148
149 @abc.abstractmethod
150 def public_bytes(
151 self,
152 encoding: _serialization.Encoding,
153 format: _serialization.PublicFormat,
154 ) -> bytes:
155 """
156 Returns the key serialized as bytes.
157 """
158
159 @abc.abstractmethod
160 def verify(
161 self,
162 signature: bytes,
163 data: bytes,
164 signature_algorithm: EllipticCurveSignatureAlgorithm,
165 ) -> None:
166 """
167 Verifies the signature of the data.
168 """
169
170 @classmethod
171 def from_encoded_point(
172 cls, curve: EllipticCurve, data: bytes
173 ) -> EllipticCurvePublicKey:
174 utils._check_bytes("data", data)
175
176 if len(data) == 0:
177 raise ValueError("data must not be an empty byte string")
178
179 if data[0] not in [0x02, 0x03, 0x04]:
180 raise ValueError("Unsupported elliptic curve point type")
181
182 return rust_openssl.ec.from_public_bytes(curve, data)
183
184 @abc.abstractmethod
185 def __eq__(self, other: object) -> bool:
186 """
187 Checks equality.
188 """
189
190
191EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey
192EllipticCurvePublicKey.register(rust_openssl.ec.ECPublicKey)
193
194EllipticCurvePrivateNumbers = rust_openssl.ec.EllipticCurvePrivateNumbers
195EllipticCurvePublicNumbers = rust_openssl.ec.EllipticCurvePublicNumbers
196
197
198class SECT571R1(EllipticCurve):
199 name = "sect571r1"
200 key_size = 570
201
202
203class SECT409R1(EllipticCurve):
204 name = "sect409r1"
205 key_size = 409
206
207
208class SECT283R1(EllipticCurve):
209 name = "sect283r1"
210 key_size = 283
211
212
213class SECT233R1(EllipticCurve):
214 name = "sect233r1"
215 key_size = 233
216
217
218class SECT163R2(EllipticCurve):
219 name = "sect163r2"
220 key_size = 163
221
222
223class SECT571K1(EllipticCurve):
224 name = "sect571k1"
225 key_size = 571
226
227
228class SECT409K1(EllipticCurve):
229 name = "sect409k1"
230 key_size = 409
231
232
233class SECT283K1(EllipticCurve):
234 name = "sect283k1"
235 key_size = 283
236
237
238class SECT233K1(EllipticCurve):
239 name = "sect233k1"
240 key_size = 233
241
242
243class SECT163K1(EllipticCurve):
244 name = "sect163k1"
245 key_size = 163
246
247
248class SECP521R1(EllipticCurve):
249 name = "secp521r1"
250 key_size = 521
251
252
253class SECP384R1(EllipticCurve):
254 name = "secp384r1"
255 key_size = 384
256
257
258class SECP256R1(EllipticCurve):
259 name = "secp256r1"
260 key_size = 256
261
262
263class SECP256K1(EllipticCurve):
264 name = "secp256k1"
265 key_size = 256
266
267
268class SECP224R1(EllipticCurve):
269 name = "secp224r1"
270 key_size = 224
271
272
273class SECP192R1(EllipticCurve):
274 name = "secp192r1"
275 key_size = 192
276
277
278class BrainpoolP256R1(EllipticCurve):
279 name = "brainpoolP256r1"
280 key_size = 256
281
282
283class BrainpoolP384R1(EllipticCurve):
284 name = "brainpoolP384r1"
285 key_size = 384
286
287
288class BrainpoolP512R1(EllipticCurve):
289 name = "brainpoolP512r1"
290 key_size = 512
291
292
293_CURVE_TYPES: dict[str, EllipticCurve] = {
294 "prime192v1": SECP192R1(),
295 "prime256v1": SECP256R1(),
296 "secp192r1": SECP192R1(),
297 "secp224r1": SECP224R1(),
298 "secp256r1": SECP256R1(),
299 "secp384r1": SECP384R1(),
300 "secp521r1": SECP521R1(),
301 "secp256k1": SECP256K1(),
302 "sect163k1": SECT163K1(),
303 "sect233k1": SECT233K1(),
304 "sect283k1": SECT283K1(),
305 "sect409k1": SECT409K1(),
306 "sect571k1": SECT571K1(),
307 "sect163r2": SECT163R2(),
308 "sect233r1": SECT233R1(),
309 "sect283r1": SECT283R1(),
310 "sect409r1": SECT409R1(),
311 "sect571r1": SECT571R1(),
312 "brainpoolP256r1": BrainpoolP256R1(),
313 "brainpoolP384r1": BrainpoolP384R1(),
314 "brainpoolP512r1": BrainpoolP512R1(),
315}
316
317
318class ECDSA(EllipticCurveSignatureAlgorithm):
319 def __init__(
320 self,
321 algorithm: asym_utils.Prehashed | hashes.HashAlgorithm,
322 ):
323 self._algorithm = algorithm
324
325 @property
326 def algorithm(
327 self,
328 ) -> asym_utils.Prehashed | hashes.HashAlgorithm:
329 return self._algorithm
330
331
332generate_private_key = rust_openssl.ec.generate_private_key
333
334
335def derive_private_key(
336 private_value: int,
337 curve: EllipticCurve,
338 backend: typing.Any = None,
339) -> EllipticCurvePrivateKey:
340 if not isinstance(private_value, int):
341 raise TypeError("private_value must be an integer type.")
342
343 if private_value <= 0:
344 raise ValueError("private_value must be a positive integer.")
345
346 return rust_openssl.ec.derive_private_key(private_value, curve)
347
348
349class ECDH:
350 pass
351
352
353_OID_TO_CURVE = {
354 EllipticCurveOID.SECP192R1: SECP192R1,
355 EllipticCurveOID.SECP224R1: SECP224R1,
356 EllipticCurveOID.SECP256K1: SECP256K1,
357 EllipticCurveOID.SECP256R1: SECP256R1,
358 EllipticCurveOID.SECP384R1: SECP384R1,
359 EllipticCurveOID.SECP521R1: SECP521R1,
360 EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1,
361 EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1,
362 EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1,
363 EllipticCurveOID.SECT163K1: SECT163K1,
364 EllipticCurveOID.SECT163R2: SECT163R2,
365 EllipticCurveOID.SECT233K1: SECT233K1,
366 EllipticCurveOID.SECT233R1: SECT233R1,
367 EllipticCurveOID.SECT283K1: SECT283K1,
368 EllipticCurveOID.SECT283R1: SECT283R1,
369 EllipticCurveOID.SECT409K1: SECT409K1,
370 EllipticCurveOID.SECT409R1: SECT409R1,
371 EllipticCurveOID.SECT571K1: SECT571K1,
372 EllipticCurveOID.SECT571R1: SECT571R1,
373}
374
375
376def get_curve_for_oid(oid: ObjectIdentifier) -> type[EllipticCurve]:
377 try:
378 return _OID_TO_CURVE[oid]
379 except KeyError:
380 raise LookupError(
381 "The provided object identifier has no matching elliptic "
382 "curve class"
383 )