ec.py 9.9 KB

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