Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py: 41%
181 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:36 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:36 +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.
6import abc
7import typing
8from math import gcd
10from cryptography.hazmat.primitives import _serialization, hashes
11from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding
12from cryptography.hazmat.primitives.asymmetric import utils as asym_utils
15class RSAPrivateKey(metaclass=abc.ABCMeta):
16 @abc.abstractmethod
17 def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes:
18 """
19 Decrypts the provided ciphertext.
20 """
22 @property
23 @abc.abstractmethod
24 def key_size(self) -> int:
25 """
26 The bit length of the public modulus.
27 """
29 @abc.abstractmethod
30 def public_key(self) -> "RSAPublicKey":
31 """
32 The RSAPublicKey associated with this private key.
33 """
35 @abc.abstractmethod
36 def sign(
37 self,
38 data: bytes,
39 padding: AsymmetricPadding,
40 algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
41 ) -> bytes:
42 """
43 Signs the data.
44 """
46 @abc.abstractmethod
47 def private_numbers(self) -> "RSAPrivateNumbers":
48 """
49 Returns an RSAPrivateNumbers.
50 """
52 @abc.abstractmethod
53 def private_bytes(
54 self,
55 encoding: _serialization.Encoding,
56 format: _serialization.PrivateFormat,
57 encryption_algorithm: _serialization.KeySerializationEncryption,
58 ) -> bytes:
59 """
60 Returns the key serialized as bytes.
61 """
64RSAPrivateKeyWithSerialization = RSAPrivateKey
67class RSAPublicKey(metaclass=abc.ABCMeta):
68 @abc.abstractmethod
69 def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes:
70 """
71 Encrypts the given plaintext.
72 """
74 @property
75 @abc.abstractmethod
76 def key_size(self) -> int:
77 """
78 The bit length of the public modulus.
79 """
81 @abc.abstractmethod
82 def public_numbers(self) -> "RSAPublicNumbers":
83 """
84 Returns an RSAPublicNumbers
85 """
87 @abc.abstractmethod
88 def public_bytes(
89 self,
90 encoding: _serialization.Encoding,
91 format: _serialization.PublicFormat,
92 ) -> bytes:
93 """
94 Returns the key serialized as bytes.
95 """
97 @abc.abstractmethod
98 def verify(
99 self,
100 signature: bytes,
101 data: bytes,
102 padding: AsymmetricPadding,
103 algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
104 ) -> None:
105 """
106 Verifies the signature of the data.
107 """
109 @abc.abstractmethod
110 def recover_data_from_signature(
111 self,
112 signature: bytes,
113 padding: AsymmetricPadding,
114 algorithm: typing.Optional[hashes.HashAlgorithm],
115 ) -> bytes:
116 """
117 Recovers the original data from the signature.
118 """
121RSAPublicKeyWithSerialization = RSAPublicKey
124def generate_private_key(
125 public_exponent: int,
126 key_size: int,
127 backend: typing.Any = None,
128) -> RSAPrivateKey:
129 from cryptography.hazmat.backends.openssl.backend import backend as ossl
131 _verify_rsa_parameters(public_exponent, key_size)
132 return ossl.generate_rsa_private_key(public_exponent, key_size)
135def _verify_rsa_parameters(public_exponent: int, key_size: int) -> None:
136 if public_exponent not in (3, 65537):
137 raise ValueError(
138 "public_exponent must be either 3 (for legacy compatibility) or "
139 "65537. Almost everyone should choose 65537 here!"
140 )
142 if key_size < 512:
143 raise ValueError("key_size must be at least 512-bits.")
146def _check_private_key_components(
147 p: int,
148 q: int,
149 private_exponent: int,
150 dmp1: int,
151 dmq1: int,
152 iqmp: int,
153 public_exponent: int,
154 modulus: int,
155) -> None:
156 if modulus < 3:
157 raise ValueError("modulus must be >= 3.")
159 if p >= modulus:
160 raise ValueError("p must be < modulus.")
162 if q >= modulus:
163 raise ValueError("q must be < modulus.")
165 if dmp1 >= modulus:
166 raise ValueError("dmp1 must be < modulus.")
168 if dmq1 >= modulus:
169 raise ValueError("dmq1 must be < modulus.")
171 if iqmp >= modulus:
172 raise ValueError("iqmp must be < modulus.")
174 if private_exponent >= modulus:
175 raise ValueError("private_exponent must be < modulus.")
177 if public_exponent < 3 or public_exponent >= modulus:
178 raise ValueError("public_exponent must be >= 3 and < modulus.")
180 if public_exponent & 1 == 0:
181 raise ValueError("public_exponent must be odd.")
183 if dmp1 & 1 == 0:
184 raise ValueError("dmp1 must be odd.")
186 if dmq1 & 1 == 0:
187 raise ValueError("dmq1 must be odd.")
189 if p * q != modulus:
190 raise ValueError("p*q must equal modulus.")
193def _check_public_key_components(e: int, n: int) -> None:
194 if n < 3:
195 raise ValueError("n must be >= 3.")
197 if e < 3 or e >= n:
198 raise ValueError("e must be >= 3 and < n.")
200 if e & 1 == 0:
201 raise ValueError("e must be odd.")
204def _modinv(e: int, m: int) -> int:
205 """
206 Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
207 """
208 x1, x2 = 1, 0
209 a, b = e, m
210 while b > 0:
211 q, r = divmod(a, b)
212 xn = x1 - q * x2
213 a, b, x1, x2 = b, r, x2, xn
214 return x1 % m
217def rsa_crt_iqmp(p: int, q: int) -> int:
218 """
219 Compute the CRT (q ** -1) % p value from RSA primes p and q.
220 """
221 return _modinv(q, p)
224def rsa_crt_dmp1(private_exponent: int, p: int) -> int:
225 """
226 Compute the CRT private_exponent % (p - 1) value from the RSA
227 private_exponent (d) and p.
228 """
229 return private_exponent % (p - 1)
232def rsa_crt_dmq1(private_exponent: int, q: int) -> int:
233 """
234 Compute the CRT private_exponent % (q - 1) value from the RSA
235 private_exponent (d) and q.
236 """
237 return private_exponent % (q - 1)
240# Controls the number of iterations rsa_recover_prime_factors will perform
241# to obtain the prime factors. Each iteration increments by 2 so the actual
242# maximum attempts is half this number.
243_MAX_RECOVERY_ATTEMPTS = 1000
246def rsa_recover_prime_factors(
247 n: int, e: int, d: int
248) -> typing.Tuple[int, int]:
249 """
250 Compute factors p and q from the private exponent d. We assume that n has
251 no more than two factors. This function is adapted from code in PyCrypto.
252 """
253 # See 8.2.2(i) in Handbook of Applied Cryptography.
254 ktot = d * e - 1
255 # The quantity d*e-1 is a multiple of phi(n), even,
256 # and can be represented as t*2^s.
257 t = ktot
258 while t % 2 == 0:
259 t = t // 2
260 # Cycle through all multiplicative inverses in Zn.
261 # The algorithm is non-deterministic, but there is a 50% chance
262 # any candidate a leads to successful factoring.
263 # See "Digitalized Signatures and Public Key Functions as Intractable
264 # as Factorization", M. Rabin, 1979
265 spotted = False
266 a = 2
267 while not spotted and a < _MAX_RECOVERY_ATTEMPTS:
268 k = t
269 # Cycle through all values a^{t*2^i}=a^k
270 while k < ktot:
271 cand = pow(a, k, n)
272 # Check if a^k is a non-trivial root of unity (mod n)
273 if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:
274 # We have found a number such that (cand-1)(cand+1)=0 (mod n).
275 # Either of the terms divides n.
276 p = gcd(cand + 1, n)
277 spotted = True
278 break
279 k *= 2
280 # This value was not any good... let's try another!
281 a += 2
282 if not spotted:
283 raise ValueError("Unable to compute factors p and q from exponent d.")
284 # Found !
285 q, r = divmod(n, p)
286 assert r == 0
287 p, q = sorted((p, q), reverse=True)
288 return (p, q)
291class RSAPrivateNumbers:
292 def __init__(
293 self,
294 p: int,
295 q: int,
296 d: int,
297 dmp1: int,
298 dmq1: int,
299 iqmp: int,
300 public_numbers: "RSAPublicNumbers",
301 ):
302 if (
303 not isinstance(p, int)
304 or not isinstance(q, int)
305 or not isinstance(d, int)
306 or not isinstance(dmp1, int)
307 or not isinstance(dmq1, int)
308 or not isinstance(iqmp, int)
309 ):
310 raise TypeError(
311 "RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must"
312 " all be an integers."
313 )
315 if not isinstance(public_numbers, RSAPublicNumbers):
316 raise TypeError(
317 "RSAPrivateNumbers public_numbers must be an RSAPublicNumbers"
318 " instance."
319 )
321 self._p = p
322 self._q = q
323 self._d = d
324 self._dmp1 = dmp1
325 self._dmq1 = dmq1
326 self._iqmp = iqmp
327 self._public_numbers = public_numbers
329 @property
330 def p(self) -> int:
331 return self._p
333 @property
334 def q(self) -> int:
335 return self._q
337 @property
338 def d(self) -> int:
339 return self._d
341 @property
342 def dmp1(self) -> int:
343 return self._dmp1
345 @property
346 def dmq1(self) -> int:
347 return self._dmq1
349 @property
350 def iqmp(self) -> int:
351 return self._iqmp
353 @property
354 def public_numbers(self) -> "RSAPublicNumbers":
355 return self._public_numbers
357 def private_key(
358 self,
359 backend: typing.Any = None,
360 *,
361 unsafe_skip_rsa_key_validation: bool = False,
362 ) -> RSAPrivateKey:
363 from cryptography.hazmat.backends.openssl.backend import (
364 backend as ossl,
365 )
367 return ossl.load_rsa_private_numbers(
368 self, unsafe_skip_rsa_key_validation
369 )
371 def __eq__(self, other: object) -> bool:
372 if not isinstance(other, RSAPrivateNumbers):
373 return NotImplemented
375 return (
376 self.p == other.p
377 and self.q == other.q
378 and self.d == other.d
379 and self.dmp1 == other.dmp1
380 and self.dmq1 == other.dmq1
381 and self.iqmp == other.iqmp
382 and self.public_numbers == other.public_numbers
383 )
385 def __hash__(self) -> int:
386 return hash(
387 (
388 self.p,
389 self.q,
390 self.d,
391 self.dmp1,
392 self.dmq1,
393 self.iqmp,
394 self.public_numbers,
395 )
396 )
399class RSAPublicNumbers:
400 def __init__(self, e: int, n: int):
401 if not isinstance(e, int) or not isinstance(n, int):
402 raise TypeError("RSAPublicNumbers arguments must be integers.")
404 self._e = e
405 self._n = n
407 @property
408 def e(self) -> int:
409 return self._e
411 @property
412 def n(self) -> int:
413 return self._n
415 def public_key(self, backend: typing.Any = None) -> RSAPublicKey:
416 from cryptography.hazmat.backends.openssl.backend import (
417 backend as ossl,
418 )
420 return ossl.load_rsa_public_numbers(self)
422 def __repr__(self) -> str:
423 return "<RSAPublicNumbers(e={0.e}, n={0.n})>".format(self)
425 def __eq__(self, other: object) -> bool:
426 if not isinstance(other, RSAPublicNumbers):
427 return NotImplemented
429 return self.e == other.e and self.n == other.n
431 def __hash__(self) -> int:
432 return hash((self.e, self.n))