rsa.py 8.3 KB

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