rsa.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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 random
  7. import typing
  8. from math import gcd
  9. from cryptography.hazmat.bindings._rust import openssl as rust_openssl
  10. from cryptography.hazmat.primitives import _serialization, hashes
  11. from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding
  12. from cryptography.hazmat.primitives.asymmetric import utils as asym_utils
  13. class RSAPrivateKey(metaclass=abc.ABCMeta):
  14. @abc.abstractmethod
  15. def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes:
  16. """
  17. Decrypts the provided ciphertext.
  18. """
  19. @property
  20. @abc.abstractmethod
  21. def key_size(self) -> int:
  22. """
  23. The bit length of the public modulus.
  24. """
  25. @abc.abstractmethod
  26. def public_key(self) -> RSAPublicKey:
  27. """
  28. The RSAPublicKey associated with this private key.
  29. """
  30. @abc.abstractmethod
  31. def sign(
  32. self,
  33. data: bytes,
  34. padding: AsymmetricPadding,
  35. algorithm: asym_utils.Prehashed | hashes.HashAlgorithm,
  36. ) -> bytes:
  37. """
  38. Signs the data.
  39. """
  40. @abc.abstractmethod
  41. def private_numbers(self) -> RSAPrivateNumbers:
  42. """
  43. Returns an RSAPrivateNumbers.
  44. """
  45. @abc.abstractmethod
  46. def private_bytes(
  47. self,
  48. encoding: _serialization.Encoding,
  49. format: _serialization.PrivateFormat,
  50. encryption_algorithm: _serialization.KeySerializationEncryption,
  51. ) -> bytes:
  52. """
  53. Returns the key serialized as bytes.
  54. """
  55. @abc.abstractmethod
  56. def __copy__(self) -> RSAPrivateKey:
  57. """
  58. Returns a copy.
  59. """
  60. RSAPrivateKeyWithSerialization = RSAPrivateKey
  61. RSAPrivateKey.register(rust_openssl.rsa.RSAPrivateKey)
  62. class RSAPublicKey(metaclass=abc.ABCMeta):
  63. @abc.abstractmethod
  64. def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes:
  65. """
  66. Encrypts the given plaintext.
  67. """
  68. @property
  69. @abc.abstractmethod
  70. def key_size(self) -> int:
  71. """
  72. The bit length of the public modulus.
  73. """
  74. @abc.abstractmethod
  75. def public_numbers(self) -> RSAPublicNumbers:
  76. """
  77. Returns an RSAPublicNumbers
  78. """
  79. @abc.abstractmethod
  80. def public_bytes(
  81. self,
  82. encoding: _serialization.Encoding,
  83. format: _serialization.PublicFormat,
  84. ) -> bytes:
  85. """
  86. Returns the key serialized as bytes.
  87. """
  88. @abc.abstractmethod
  89. def verify(
  90. self,
  91. signature: bytes,
  92. data: bytes,
  93. padding: AsymmetricPadding,
  94. algorithm: asym_utils.Prehashed | hashes.HashAlgorithm,
  95. ) -> None:
  96. """
  97. Verifies the signature of the data.
  98. """
  99. @abc.abstractmethod
  100. def recover_data_from_signature(
  101. self,
  102. signature: bytes,
  103. padding: AsymmetricPadding,
  104. algorithm: hashes.HashAlgorithm | None,
  105. ) -> bytes:
  106. """
  107. Recovers the original data from the signature.
  108. """
  109. @abc.abstractmethod
  110. def __eq__(self, other: object) -> bool:
  111. """
  112. Checks equality.
  113. """
  114. @abc.abstractmethod
  115. def __copy__(self) -> RSAPublicKey:
  116. """
  117. Returns a copy.
  118. """
  119. RSAPublicKeyWithSerialization = RSAPublicKey
  120. RSAPublicKey.register(rust_openssl.rsa.RSAPublicKey)
  121. RSAPrivateNumbers = rust_openssl.rsa.RSAPrivateNumbers
  122. RSAPublicNumbers = rust_openssl.rsa.RSAPublicNumbers
  123. def generate_private_key(
  124. public_exponent: int,
  125. key_size: int,
  126. backend: typing.Any = None,
  127. ) -> RSAPrivateKey:
  128. _verify_rsa_parameters(public_exponent, key_size)
  129. return rust_openssl.rsa.generate_private_key(public_exponent, key_size)
  130. def _verify_rsa_parameters(public_exponent: int, key_size: int) -> None:
  131. if public_exponent not in (3, 65537):
  132. raise ValueError(
  133. "public_exponent must be either 3 (for legacy compatibility) or "
  134. "65537. Almost everyone should choose 65537 here!"
  135. )
  136. if key_size < 1024:
  137. raise ValueError("key_size must be at least 1024-bits.")
  138. def _modinv(e: int, m: int) -> int:
  139. """
  140. Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
  141. """
  142. x1, x2 = 1, 0
  143. a, b = e, m
  144. while b > 0:
  145. q, r = divmod(a, b)
  146. xn = x1 - q * x2
  147. a, b, x1, x2 = b, r, x2, xn
  148. return x1 % m
  149. def rsa_crt_iqmp(p: int, q: int) -> int:
  150. """
  151. Compute the CRT (q ** -1) % p value from RSA primes p and q.
  152. """
  153. if p <= 1 or q <= 1:
  154. raise ValueError("Values can't be <= 1")
  155. return _modinv(q, p)
  156. def rsa_crt_dmp1(private_exponent: int, p: int) -> int:
  157. """
  158. Compute the CRT private_exponent % (p - 1) value from the RSA
  159. private_exponent (d) and p.
  160. """
  161. if private_exponent <= 1 or p <= 1:
  162. raise ValueError("Values can't be <= 1")
  163. return private_exponent % (p - 1)
  164. def rsa_crt_dmq1(private_exponent: int, q: int) -> int:
  165. """
  166. Compute the CRT private_exponent % (q - 1) value from the RSA
  167. private_exponent (d) and q.
  168. """
  169. if private_exponent <= 1 or q <= 1:
  170. raise ValueError("Values can't be <= 1")
  171. return private_exponent % (q - 1)
  172. def rsa_recover_private_exponent(e: int, p: int, q: int) -> int:
  173. """
  174. Compute the RSA private_exponent (d) given the public exponent (e)
  175. and the RSA primes p and q.
  176. This uses the Carmichael totient function to generate the
  177. smallest possible working value of the private exponent.
  178. """
  179. # This lambda_n is the Carmichael totient function.
  180. # The original RSA paper uses the Euler totient function
  181. # here: phi_n = (p - 1) * (q - 1)
  182. # Either version of the private exponent will work, but the
  183. # one generated by the older formulation may be larger
  184. # than necessary. (lambda_n always divides phi_n)
  185. #
  186. # TODO: Replace with lcm(p - 1, q - 1) once the minimum
  187. # supported Python version is >= 3.9.
  188. if e <= 1 or p <= 1 or q <= 1:
  189. raise ValueError("Values can't be <= 1")
  190. lambda_n = (p - 1) * (q - 1) // gcd(p - 1, q - 1)
  191. return _modinv(e, lambda_n)
  192. # Controls the number of iterations rsa_recover_prime_factors will perform
  193. # to obtain the prime factors.
  194. _MAX_RECOVERY_ATTEMPTS = 500
  195. def rsa_recover_prime_factors(n: int, e: int, d: int) -> tuple[int, int]:
  196. """
  197. Compute factors p and q from the private exponent d. We assume that n has
  198. no more than two factors. This function is adapted from code in PyCrypto.
  199. """
  200. # reject invalid values early
  201. if d <= 1 or e <= 1:
  202. raise ValueError("d, e can't be <= 1")
  203. if 17 != pow(17, e * d, n):
  204. raise ValueError("n, d, e don't match")
  205. # See 8.2.2(i) in Handbook of Applied Cryptography.
  206. ktot = d * e - 1
  207. # The quantity d*e-1 is a multiple of phi(n), even,
  208. # and can be represented as t*2^s.
  209. t = ktot
  210. while t % 2 == 0:
  211. t = t // 2
  212. # Cycle through all multiplicative inverses in Zn.
  213. # The algorithm is non-deterministic, but there is a 50% chance
  214. # any candidate a leads to successful factoring.
  215. # See "Digitalized Signatures and Public Key Functions as Intractable
  216. # as Factorization", M. Rabin, 1979
  217. spotted = False
  218. tries = 0
  219. while not spotted and tries < _MAX_RECOVERY_ATTEMPTS:
  220. a = random.randint(2, n - 1)
  221. tries += 1
  222. k = t
  223. # Cycle through all values a^{t*2^i}=a^k
  224. while k < ktot:
  225. cand = pow(a, k, n)
  226. # Check if a^k is a non-trivial root of unity (mod n)
  227. if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:
  228. # We have found a number such that (cand-1)(cand+1)=0 (mod n).
  229. # Either of the terms divides n.
  230. p = gcd(cand + 1, n)
  231. spotted = True
  232. break
  233. k *= 2
  234. if not spotted:
  235. raise ValueError("Unable to compute factors p and q from exponent d.")
  236. # Found !
  237. q, r = divmod(n, p)
  238. assert r == 0
  239. p, q = sorted((p, q), reverse=True)
  240. return (p, q)