ec.py 10 KB

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