Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py: 44%
186 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 07:26 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 07:26 +0000
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.
5from __future__ import annotations
7import abc
8import typing
9from math import gcd
11from cryptography.hazmat.bindings._rust import openssl as rust_openssl
12from cryptography.hazmat.primitives import _serialization, hashes
13from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding
14from cryptography.hazmat.primitives.asymmetric import utils as asym_utils
17class RSAPrivateKey(metaclass=abc.ABCMeta):
18 @abc.abstractmethod
19 def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes:
20 """
21 Decrypts the provided ciphertext.
22 """
24 @property
25 @abc.abstractmethod
26 def key_size(self) -> int:
27 """
28 The bit length of the public modulus.
29 """
31 @abc.abstractmethod
32 def public_key(self) -> RSAPublicKey:
33 """
34 The RSAPublicKey associated with this private key.
35 """
37 @abc.abstractmethod
38 def sign(
39 self,
40 data: bytes,
41 padding: AsymmetricPadding,
42 algorithm: asym_utils.Prehashed | hashes.HashAlgorithm,
43 ) -> bytes:
44 """
45 Signs the data.
46 """
48 @abc.abstractmethod
49 def private_numbers(self) -> RSAPrivateNumbers:
50 """
51 Returns an RSAPrivateNumbers.
52 """
54 @abc.abstractmethod
55 def private_bytes(
56 self,
57 encoding: _serialization.Encoding,
58 format: _serialization.PrivateFormat,
59 encryption_algorithm: _serialization.KeySerializationEncryption,
60 ) -> bytes:
61 """
62 Returns the key serialized as bytes.
63 """
66RSAPrivateKeyWithSerialization = RSAPrivateKey
67RSAPrivateKey.register(rust_openssl.rsa.RSAPrivateKey)
70class RSAPublicKey(metaclass=abc.ABCMeta):
71 @abc.abstractmethod
72 def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes:
73 """
74 Encrypts the given plaintext.
75 """
77 @property
78 @abc.abstractmethod
79 def key_size(self) -> int:
80 """
81 The bit length of the public modulus.
82 """
84 @abc.abstractmethod
85 def public_numbers(self) -> RSAPublicNumbers:
86 """
87 Returns an RSAPublicNumbers
88 """
90 @abc.abstractmethod
91 def public_bytes(
92 self,
93 encoding: _serialization.Encoding,
94 format: _serialization.PublicFormat,
95 ) -> bytes:
96 """
97 Returns the key serialized as bytes.
98 """
100 @abc.abstractmethod
101 def verify(
102 self,
103 signature: bytes,
104 data: bytes,
105 padding: AsymmetricPadding,
106 algorithm: asym_utils.Prehashed | hashes.HashAlgorithm,
107 ) -> None:
108 """
109 Verifies the signature of the data.
110 """
112 @abc.abstractmethod
113 def recover_data_from_signature(
114 self,
115 signature: bytes,
116 padding: AsymmetricPadding,
117 algorithm: hashes.HashAlgorithm | None,
118 ) -> bytes:
119 """
120 Recovers the original data from the signature.
121 """
123 @abc.abstractmethod
124 def __eq__(self, other: object) -> bool:
125 """
126 Checks equality.
127 """
130RSAPublicKeyWithSerialization = RSAPublicKey
131RSAPublicKey.register(rust_openssl.rsa.RSAPublicKey)
134def generate_private_key(
135 public_exponent: int,
136 key_size: int,
137 backend: typing.Any = None,
138) -> RSAPrivateKey:
139 _verify_rsa_parameters(public_exponent, key_size)
140 return rust_openssl.rsa.generate_private_key(public_exponent, key_size)
143def _verify_rsa_parameters(public_exponent: int, key_size: int) -> None:
144 if public_exponent not in (3, 65537):
145 raise ValueError(
146 "public_exponent must be either 3 (for legacy compatibility) or "
147 "65537. Almost everyone should choose 65537 here!"
148 )
150 if key_size < 512:
151 raise ValueError("key_size must be at least 512-bits.")
154def _check_private_key_components(
155 p: int,
156 q: int,
157 private_exponent: int,
158 dmp1: int,
159 dmq1: int,
160 iqmp: int,
161 public_exponent: int,
162 modulus: int,
163) -> None:
164 if modulus < 3:
165 raise ValueError("modulus must be >= 3.")
167 if p >= modulus:
168 raise ValueError("p must be < modulus.")
170 if q >= modulus:
171 raise ValueError("q must be < modulus.")
173 if dmp1 >= modulus:
174 raise ValueError("dmp1 must be < modulus.")
176 if dmq1 >= modulus:
177 raise ValueError("dmq1 must be < modulus.")
179 if iqmp >= modulus:
180 raise ValueError("iqmp must be < modulus.")
182 if private_exponent >= modulus:
183 raise ValueError("private_exponent must be < modulus.")
185 if public_exponent < 3 or public_exponent >= modulus:
186 raise ValueError("public_exponent must be >= 3 and < modulus.")
188 if public_exponent & 1 == 0:
189 raise ValueError("public_exponent must be odd.")
191 if dmp1 & 1 == 0:
192 raise ValueError("dmp1 must be odd.")
194 if dmq1 & 1 == 0:
195 raise ValueError("dmq1 must be odd.")
197 if p * q != modulus:
198 raise ValueError("p*q must equal modulus.")
201def _check_public_key_components(e: int, n: int) -> None:
202 if n < 3:
203 raise ValueError("n must be >= 3.")
205 if e < 3 or e >= n:
206 raise ValueError("e must be >= 3 and < n.")
208 if e & 1 == 0:
209 raise ValueError("e must be odd.")
212def _modinv(e: int, m: int) -> int:
213 """
214 Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
215 """
216 x1, x2 = 1, 0
217 a, b = e, m
218 while b > 0:
219 q, r = divmod(a, b)
220 xn = x1 - q * x2
221 a, b, x1, x2 = b, r, x2, xn
222 return x1 % m
225def rsa_crt_iqmp(p: int, q: int) -> int:
226 """
227 Compute the CRT (q ** -1) % p value from RSA primes p and q.
228 """
229 return _modinv(q, p)
232def rsa_crt_dmp1(private_exponent: int, p: int) -> int:
233 """
234 Compute the CRT private_exponent % (p - 1) value from the RSA
235 private_exponent (d) and p.
236 """
237 return private_exponent % (p - 1)
240def rsa_crt_dmq1(private_exponent: int, q: int) -> int:
241 """
242 Compute the CRT private_exponent % (q - 1) value from the RSA
243 private_exponent (d) and q.
244 """
245 return private_exponent % (q - 1)
248# Controls the number of iterations rsa_recover_prime_factors will perform
249# to obtain the prime factors. Each iteration increments by 2 so the actual
250# maximum attempts is half this number.
251_MAX_RECOVERY_ATTEMPTS = 1000
254def rsa_recover_prime_factors(n: int, e: int, d: int) -> tuple[int, int]:
255 """
256 Compute factors p and q from the private exponent d. We assume that n has
257 no more than two factors. This function is adapted from code in PyCrypto.
258 """
259 # See 8.2.2(i) in Handbook of Applied Cryptography.
260 ktot = d * e - 1
261 # The quantity d*e-1 is a multiple of phi(n), even,
262 # and can be represented as t*2^s.
263 t = ktot
264 while t % 2 == 0:
265 t = t // 2
266 # Cycle through all multiplicative inverses in Zn.
267 # The algorithm is non-deterministic, but there is a 50% chance
268 # any candidate a leads to successful factoring.
269 # See "Digitalized Signatures and Public Key Functions as Intractable
270 # as Factorization", M. Rabin, 1979
271 spotted = False
272 a = 2
273 while not spotted and a < _MAX_RECOVERY_ATTEMPTS:
274 k = t
275 # Cycle through all values a^{t*2^i}=a^k
276 while k < ktot:
277 cand = pow(a, k, n)
278 # Check if a^k is a non-trivial root of unity (mod n)
279 if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:
280 # We have found a number such that (cand-1)(cand+1)=0 (mod n).
281 # Either of the terms divides n.
282 p = gcd(cand + 1, n)
283 spotted = True
284 break
285 k *= 2
286 # This value was not any good... let's try another!
287 a += 2
288 if not spotted:
289 raise ValueError("Unable to compute factors p and q from exponent d.")
290 # Found !
291 q, r = divmod(n, p)
292 assert r == 0
293 p, q = sorted((p, q), reverse=True)
294 return (p, q)
297class RSAPrivateNumbers:
298 def __init__(
299 self,
300 p: int,
301 q: int,
302 d: int,
303 dmp1: int,
304 dmq1: int,
305 iqmp: int,
306 public_numbers: RSAPublicNumbers,
307 ):
308 if (
309 not isinstance(p, int)
310 or not isinstance(q, int)
311 or not isinstance(d, int)
312 or not isinstance(dmp1, int)
313 or not isinstance(dmq1, int)
314 or not isinstance(iqmp, int)
315 ):
316 raise TypeError(
317 "RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must"
318 " all be an integers."
319 )
321 if not isinstance(public_numbers, RSAPublicNumbers):
322 raise TypeError(
323 "RSAPrivateNumbers public_numbers must be an RSAPublicNumbers"
324 " instance."
325 )
327 self._p = p
328 self._q = q
329 self._d = d
330 self._dmp1 = dmp1
331 self._dmq1 = dmq1
332 self._iqmp = iqmp
333 self._public_numbers = public_numbers
335 @property
336 def p(self) -> int:
337 return self._p
339 @property
340 def q(self) -> int:
341 return self._q
343 @property
344 def d(self) -> int:
345 return self._d
347 @property
348 def dmp1(self) -> int:
349 return self._dmp1
351 @property
352 def dmq1(self) -> int:
353 return self._dmq1
355 @property
356 def iqmp(self) -> int:
357 return self._iqmp
359 @property
360 def public_numbers(self) -> RSAPublicNumbers:
361 return self._public_numbers
363 def private_key(
364 self,
365 backend: typing.Any = None,
366 *,
367 unsafe_skip_rsa_key_validation: bool = False,
368 ) -> RSAPrivateKey:
369 _check_private_key_components(
370 self.p,
371 self.q,
372 self.d,
373 self.dmp1,
374 self.dmq1,
375 self.iqmp,
376 self.public_numbers.e,
377 self.public_numbers.n,
378 )
379 return rust_openssl.rsa.from_private_numbers(
380 self, unsafe_skip_rsa_key_validation
381 )
383 def __eq__(self, other: object) -> bool:
384 if not isinstance(other, RSAPrivateNumbers):
385 return NotImplemented
387 return (
388 self.p == other.p
389 and self.q == other.q
390 and self.d == other.d
391 and self.dmp1 == other.dmp1
392 and self.dmq1 == other.dmq1
393 and self.iqmp == other.iqmp
394 and self.public_numbers == other.public_numbers
395 )
397 def __hash__(self) -> int:
398 return hash(
399 (
400 self.p,
401 self.q,
402 self.d,
403 self.dmp1,
404 self.dmq1,
405 self.iqmp,
406 self.public_numbers,
407 )
408 )
411class RSAPublicNumbers:
412 def __init__(self, e: int, n: int):
413 if not isinstance(e, int) or not isinstance(n, int):
414 raise TypeError("RSAPublicNumbers arguments must be integers.")
416 self._e = e
417 self._n = n
419 @property
420 def e(self) -> int:
421 return self._e
423 @property
424 def n(self) -> int:
425 return self._n
427 def public_key(self, backend: typing.Any = None) -> RSAPublicKey:
428 _check_public_key_components(self.e, self.n)
429 return rust_openssl.rsa.from_public_numbers(self)
431 def __repr__(self) -> str:
432 return f"<RSAPublicNumbers(e={self.e}, n={self.n})>"
434 def __eq__(self, other: object) -> bool:
435 if not isinstance(other, RSAPublicNumbers):
436 return NotImplemented
438 return self.e == other.e and self.n == other.n
440 def __hash__(self) -> int:
441 return hash((self.e, self.n))