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