Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py : 71%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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.
6import abc
7import typing
8import warnings
10from cryptography import utils
11from cryptography.hazmat._oid import ObjectIdentifier
12from cryptography.hazmat.backends import _get_backend
13from cryptography.hazmat.primitives import _serialization, hashes
14from cryptography.hazmat.primitives.asymmetric import (
15 AsymmetricSignatureContext,
16 AsymmetricVerificationContext,
17 utils as asym_utils,
18)
21class EllipticCurveOID(object):
22 SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1")
23 SECP224R1 = ObjectIdentifier("1.3.132.0.33")
24 SECP256K1 = ObjectIdentifier("1.3.132.0.10")
25 SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7")
26 SECP384R1 = ObjectIdentifier("1.3.132.0.34")
27 SECP521R1 = ObjectIdentifier("1.3.132.0.35")
28 BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7")
29 BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11")
30 BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13")
31 SECT163K1 = ObjectIdentifier("1.3.132.0.1")
32 SECT163R2 = ObjectIdentifier("1.3.132.0.15")
33 SECT233K1 = ObjectIdentifier("1.3.132.0.26")
34 SECT233R1 = ObjectIdentifier("1.3.132.0.27")
35 SECT283K1 = ObjectIdentifier("1.3.132.0.16")
36 SECT283R1 = ObjectIdentifier("1.3.132.0.17")
37 SECT409K1 = ObjectIdentifier("1.3.132.0.36")
38 SECT409R1 = ObjectIdentifier("1.3.132.0.37")
39 SECT571K1 = ObjectIdentifier("1.3.132.0.38")
40 SECT571R1 = ObjectIdentifier("1.3.132.0.39")
43class EllipticCurve(metaclass=abc.ABCMeta):
44 @abc.abstractproperty
45 def name(self) -> str:
46 """
47 The name of the curve. e.g. secp256r1.
48 """
50 @abc.abstractproperty
51 def key_size(self) -> int:
52 """
53 Bit size of a secret scalar for the curve.
54 """
57class EllipticCurveSignatureAlgorithm(metaclass=abc.ABCMeta):
58 @abc.abstractproperty
59 def algorithm(
60 self,
61 ) -> typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm]:
62 """
63 The digest algorithm used with this signature.
64 """
67class EllipticCurvePrivateKey(metaclass=abc.ABCMeta):
68 @abc.abstractmethod
69 def signer(
70 self,
71 signature_algorithm: EllipticCurveSignatureAlgorithm,
72 ) -> AsymmetricSignatureContext:
73 """
74 Returns an AsymmetricSignatureContext used for signing data.
75 """
77 @abc.abstractmethod
78 def exchange(
79 self, algorithm: "ECDH", peer_public_key: "EllipticCurvePublicKey"
80 ) -> bytes:
81 """
82 Performs a key exchange operation using the provided algorithm with the
83 provided peer's public key.
84 """
86 @abc.abstractmethod
87 def public_key(self) -> "EllipticCurvePublicKey":
88 """
89 The EllipticCurvePublicKey for this private key.
90 """
92 @abc.abstractproperty
93 def curve(self) -> EllipticCurve:
94 """
95 The EllipticCurve that this key is on.
96 """
98 @abc.abstractproperty
99 def key_size(self) -> int:
100 """
101 Bit size of a secret scalar for the curve.
102 """
104 @abc.abstractmethod
105 def sign(
106 self,
107 data,
108 signature_algorithm: EllipticCurveSignatureAlgorithm,
109 ) -> bytes:
110 """
111 Signs the data
112 """
114 @abc.abstractmethod
115 def private_numbers(self) -> "EllipticCurvePrivateNumbers":
116 """
117 Returns an EllipticCurvePrivateNumbers.
118 """
120 @abc.abstractmethod
121 def private_bytes(
122 self,
123 encoding: _serialization.Encoding,
124 format: _serialization.PrivateFormat,
125 encryption_algorithm: _serialization.KeySerializationEncryption,
126 ) -> bytes:
127 """
128 Returns the key serialized as bytes.
129 """
132EllipticCurvePrivateKeyWithSerialization = EllipticCurvePrivateKey
135class EllipticCurvePublicKey(metaclass=abc.ABCMeta):
136 @abc.abstractmethod
137 def verifier(
138 self,
139 signature: bytes,
140 signature_algorithm: EllipticCurveSignatureAlgorithm,
141 ) -> AsymmetricVerificationContext:
142 """
143 Returns an AsymmetricVerificationContext used for signing data.
144 """
146 @abc.abstractproperty
147 def curve(self) -> EllipticCurve:
148 """
149 The EllipticCurve that this key is on.
150 """
152 @abc.abstractproperty
153 def key_size(self) -> int:
154 """
155 Bit size of a secret scalar for the curve.
156 """
158 @abc.abstractmethod
159 def public_numbers(self) -> "EllipticCurvePublicNumbers":
160 """
161 Returns an EllipticCurvePublicNumbers.
162 """
164 @abc.abstractmethod
165 def public_bytes(
166 self,
167 encoding: _serialization.Encoding,
168 format: _serialization.PublicFormat,
169 ) -> bytes:
170 """
171 Returns the key serialized as bytes.
172 """
174 @abc.abstractmethod
175 def verify(
176 self,
177 signature: bytes,
178 data: bytes,
179 signature_algorithm: EllipticCurveSignatureAlgorithm,
180 ) -> None:
181 """
182 Verifies the signature of the data.
183 """
185 @classmethod
186 def from_encoded_point(
187 cls, curve: EllipticCurve, data: bytes
188 ) -> "EllipticCurvePublicKey":
189 utils._check_bytes("data", data)
191 if not isinstance(curve, EllipticCurve):
192 raise TypeError("curve must be an EllipticCurve instance")
194 if len(data) == 0:
195 raise ValueError("data must not be an empty byte string")
197 if data[0] not in [0x02, 0x03, 0x04]:
198 raise ValueError("Unsupported elliptic curve point type")
200 from cryptography.hazmat.backends.openssl.backend import backend
202 return backend.load_elliptic_curve_public_bytes(curve, data)
205EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey
208class SECT571R1(EllipticCurve):
209 name = "sect571r1"
210 key_size = 570
213class SECT409R1(EllipticCurve):
214 name = "sect409r1"
215 key_size = 409
218class SECT283R1(EllipticCurve):
219 name = "sect283r1"
220 key_size = 283
223class SECT233R1(EllipticCurve):
224 name = "sect233r1"
225 key_size = 233
228class SECT163R2(EllipticCurve):
229 name = "sect163r2"
230 key_size = 163
233class SECT571K1(EllipticCurve):
234 name = "sect571k1"
235 key_size = 571
238class SECT409K1(EllipticCurve):
239 name = "sect409k1"
240 key_size = 409
243class SECT283K1(EllipticCurve):
244 name = "sect283k1"
245 key_size = 283
248class SECT233K1(EllipticCurve):
249 name = "sect233k1"
250 key_size = 233
253class SECT163K1(EllipticCurve):
254 name = "sect163k1"
255 key_size = 163
258class SECP521R1(EllipticCurve):
259 name = "secp521r1"
260 key_size = 521
263class SECP384R1(EllipticCurve):
264 name = "secp384r1"
265 key_size = 384
268class SECP256R1(EllipticCurve):
269 name = "secp256r1"
270 key_size = 256
273class SECP256K1(EllipticCurve):
274 name = "secp256k1"
275 key_size = 256
278class SECP224R1(EllipticCurve):
279 name = "secp224r1"
280 key_size = 224
283class SECP192R1(EllipticCurve):
284 name = "secp192r1"
285 key_size = 192
288class BrainpoolP256R1(EllipticCurve):
289 name = "brainpoolP256r1"
290 key_size = 256
293class BrainpoolP384R1(EllipticCurve):
294 name = "brainpoolP384r1"
295 key_size = 384
298class BrainpoolP512R1(EllipticCurve):
299 name = "brainpoolP512r1"
300 key_size = 512
303_CURVE_TYPES: typing.Dict[str, typing.Type[EllipticCurve]] = {
304 "prime192v1": SECP192R1,
305 "prime256v1": SECP256R1,
306 "secp192r1": SECP192R1,
307 "secp224r1": SECP224R1,
308 "secp256r1": SECP256R1,
309 "secp384r1": SECP384R1,
310 "secp521r1": SECP521R1,
311 "secp256k1": SECP256K1,
312 "sect163k1": SECT163K1,
313 "sect233k1": SECT233K1,
314 "sect283k1": SECT283K1,
315 "sect409k1": SECT409K1,
316 "sect571k1": SECT571K1,
317 "sect163r2": SECT163R2,
318 "sect233r1": SECT233R1,
319 "sect283r1": SECT283R1,
320 "sect409r1": SECT409R1,
321 "sect571r1": SECT571R1,
322 "brainpoolP256r1": BrainpoolP256R1,
323 "brainpoolP384r1": BrainpoolP384R1,
324 "brainpoolP512r1": BrainpoolP512R1,
325}
328class ECDSA(EllipticCurveSignatureAlgorithm):
329 def __init__(self, algorithm):
330 self._algorithm = algorithm
332 algorithm = utils.read_only_property("_algorithm")
335def generate_private_key(
336 curve: EllipticCurve, backend=None
337) -> EllipticCurvePrivateKey:
338 backend = _get_backend(backend)
339 return backend.generate_elliptic_curve_private_key(curve)
342def derive_private_key(
343 private_value: int, curve: EllipticCurve, backend=None
344) -> EllipticCurvePrivateKey:
345 backend = _get_backend(backend)
346 if not isinstance(private_value, int):
347 raise TypeError("private_value must be an integer type.")
349 if private_value <= 0:
350 raise ValueError("private_value must be a positive integer.")
352 if not isinstance(curve, EllipticCurve):
353 raise TypeError("curve must provide the EllipticCurve interface.")
355 return backend.derive_elliptic_curve_private_key(private_value, curve)
358class EllipticCurvePublicNumbers(object):
359 def __init__(self, x: int, y: int, curve: EllipticCurve):
360 if not isinstance(x, int) or not isinstance(y, int):
361 raise TypeError("x and y must be integers.")
363 if not isinstance(curve, EllipticCurve):
364 raise TypeError("curve must provide the EllipticCurve interface.")
366 self._y = y
367 self._x = x
368 self._curve = curve
370 def public_key(self, backend=None) -> EllipticCurvePublicKey:
371 backend = _get_backend(backend)
372 return backend.load_elliptic_curve_public_numbers(self)
374 def encode_point(self) -> bytes:
375 warnings.warn(
376 "encode_point has been deprecated on EllipticCurvePublicNumbers"
377 " and will be removed in a future version. Please use "
378 "EllipticCurvePublicKey.public_bytes to obtain both "
379 "compressed and uncompressed point encoding.",
380 utils.PersistentlyDeprecated2019,
381 stacklevel=2,
382 )
383 # key_size is in bits. Convert to bytes and round up
384 byte_length = (self.curve.key_size + 7) // 8
385 return (
386 b"\x04"
387 + utils.int_to_bytes(self.x, byte_length)
388 + utils.int_to_bytes(self.y, byte_length)
389 )
391 @classmethod
392 def from_encoded_point(
393 cls, curve: EllipticCurve, data: bytes
394 ) -> "EllipticCurvePublicNumbers":
395 if not isinstance(curve, EllipticCurve):
396 raise TypeError("curve must be an EllipticCurve instance")
398 warnings.warn(
399 "Support for unsafe construction of public numbers from "
400 "encoded data will be removed in a future version. "
401 "Please use EllipticCurvePublicKey.from_encoded_point",
402 utils.PersistentlyDeprecated2019,
403 stacklevel=2,
404 )
406 if data.startswith(b"\x04"):
407 # key_size is in bits. Convert to bytes and round up
408 byte_length = (curve.key_size + 7) // 8
409 if len(data) == 2 * byte_length + 1:
410 x = int.from_bytes(data[1 : byte_length + 1], "big")
411 y = int.from_bytes(data[byte_length + 1 :], "big")
412 return cls(x, y, curve)
413 else:
414 raise ValueError("Invalid elliptic curve point data length")
415 else:
416 raise ValueError("Unsupported elliptic curve point type")
418 curve = utils.read_only_property("_curve")
419 x = utils.read_only_property("_x")
420 y = utils.read_only_property("_y")
422 def __eq__(self, other):
423 if not isinstance(other, EllipticCurvePublicNumbers):
424 return NotImplemented
426 return (
427 self.x == other.x
428 and self.y == other.y
429 and self.curve.name == other.curve.name
430 and self.curve.key_size == other.curve.key_size
431 )
433 def __ne__(self, other):
434 return not self == other
436 def __hash__(self):
437 return hash((self.x, self.y, self.curve.name, self.curve.key_size))
439 def __repr__(self):
440 return (
441 "<EllipticCurvePublicNumbers(curve={0.curve.name}, x={0.x}, "
442 "y={0.y}>".format(self)
443 )
446class EllipticCurvePrivateNumbers(object):
447 def __init__(
448 self, private_value: int, public_numbers: EllipticCurvePublicNumbers
449 ):
450 if not isinstance(private_value, int):
451 raise TypeError("private_value must be an integer.")
453 if not isinstance(public_numbers, EllipticCurvePublicNumbers):
454 raise TypeError(
455 "public_numbers must be an EllipticCurvePublicNumbers "
456 "instance."
457 )
459 self._private_value = private_value
460 self._public_numbers = public_numbers
462 def private_key(self, backend=None) -> EllipticCurvePrivateKey:
463 backend = _get_backend(backend)
464 return backend.load_elliptic_curve_private_numbers(self)
466 private_value = utils.read_only_property("_private_value")
467 public_numbers = utils.read_only_property("_public_numbers")
469 def __eq__(self, other):
470 if not isinstance(other, EllipticCurvePrivateNumbers):
471 return NotImplemented
473 return (
474 self.private_value == other.private_value
475 and self.public_numbers == other.public_numbers
476 )
478 def __ne__(self, other):
479 return not self == other
481 def __hash__(self):
482 return hash((self.private_value, self.public_numbers))
485class ECDH(object):
486 pass
489_OID_TO_CURVE = {
490 EllipticCurveOID.SECP192R1: SECP192R1,
491 EllipticCurveOID.SECP224R1: SECP224R1,
492 EllipticCurveOID.SECP256K1: SECP256K1,
493 EllipticCurveOID.SECP256R1: SECP256R1,
494 EllipticCurveOID.SECP384R1: SECP384R1,
495 EllipticCurveOID.SECP521R1: SECP521R1,
496 EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1,
497 EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1,
498 EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1,
499 EllipticCurveOID.SECT163K1: SECT163K1,
500 EllipticCurveOID.SECT163R2: SECT163R2,
501 EllipticCurveOID.SECT233K1: SECT233K1,
502 EllipticCurveOID.SECT233R1: SECT233R1,
503 EllipticCurveOID.SECT283K1: SECT283K1,
504 EllipticCurveOID.SECT283R1: SECT283R1,
505 EllipticCurveOID.SECT409K1: SECT409K1,
506 EllipticCurveOID.SECT409R1: SECT409R1,
507 EllipticCurveOID.SECT571K1: SECT571K1,
508 EllipticCurveOID.SECT571R1: SECT571R1,
509}
512def get_curve_for_oid(oid: ObjectIdentifier) -> typing.Type[EllipticCurve]:
513 try:
514 return _OID_TO_CURVE[oid]
515 except KeyError:
516 raise LookupError(
517 "The provided object identifier has no matching elliptic "
518 "curve class"
519 )