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