Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py: 42%

184 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:05 +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. 

4 

5from __future__ import annotations 

6 

7import abc 

8import typing 

9from math import gcd 

10 

11from cryptography.hazmat.primitives import _serialization, hashes 

12from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding 

13from cryptography.hazmat.primitives.asymmetric import utils as asym_utils 

14 

15 

16class RSAPrivateKey(metaclass=abc.ABCMeta): 

17 @abc.abstractmethod 

18 def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes: 

19 """ 

20 Decrypts the provided ciphertext. 

21 """ 

22 

23 @property 

24 @abc.abstractmethod 

25 def key_size(self) -> int: 

26 """ 

27 The bit length of the public modulus. 

28 """ 

29 

30 @abc.abstractmethod 

31 def public_key(self) -> RSAPublicKey: 

32 """ 

33 The RSAPublicKey associated with this private key. 

34 """ 

35 

36 @abc.abstractmethod 

37 def sign( 

38 self, 

39 data: bytes, 

40 padding: AsymmetricPadding, 

41 algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], 

42 ) -> bytes: 

43 """ 

44 Signs the data. 

45 """ 

46 

47 @abc.abstractmethod 

48 def private_numbers(self) -> RSAPrivateNumbers: 

49 """ 

50 Returns an RSAPrivateNumbers. 

51 """ 

52 

53 @abc.abstractmethod 

54 def private_bytes( 

55 self, 

56 encoding: _serialization.Encoding, 

57 format: _serialization.PrivateFormat, 

58 encryption_algorithm: _serialization.KeySerializationEncryption, 

59 ) -> bytes: 

60 """ 

61 Returns the key serialized as bytes. 

62 """ 

63 

64 

65RSAPrivateKeyWithSerialization = RSAPrivateKey 

66 

67 

68class RSAPublicKey(metaclass=abc.ABCMeta): 

69 @abc.abstractmethod 

70 def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes: 

71 """ 

72 Encrypts the given plaintext. 

73 """ 

74 

75 @property 

76 @abc.abstractmethod 

77 def key_size(self) -> int: 

78 """ 

79 The bit length of the public modulus. 

80 """ 

81 

82 @abc.abstractmethod 

83 def public_numbers(self) -> RSAPublicNumbers: 

84 """ 

85 Returns an RSAPublicNumbers 

86 """ 

87 

88 @abc.abstractmethod 

89 def public_bytes( 

90 self, 

91 encoding: _serialization.Encoding, 

92 format: _serialization.PublicFormat, 

93 ) -> bytes: 

94 """ 

95 Returns the key serialized as bytes. 

96 """ 

97 

98 @abc.abstractmethod 

99 def verify( 

100 self, 

101 signature: bytes, 

102 data: bytes, 

103 padding: AsymmetricPadding, 

104 algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], 

105 ) -> None: 

106 """ 

107 Verifies the signature of the data. 

108 """ 

109 

110 @abc.abstractmethod 

111 def recover_data_from_signature( 

112 self, 

113 signature: bytes, 

114 padding: AsymmetricPadding, 

115 algorithm: typing.Optional[hashes.HashAlgorithm], 

116 ) -> bytes: 

117 """ 

118 Recovers the original data from the signature. 

119 """ 

120 

121 @abc.abstractmethod 

122 def __eq__(self, other: object) -> bool: 

123 """ 

124 Checks equality. 

125 """ 

126 

127 

128RSAPublicKeyWithSerialization = RSAPublicKey 

129 

130 

131def generate_private_key( 

132 public_exponent: int, 

133 key_size: int, 

134 backend: typing.Any = None, 

135) -> RSAPrivateKey: 

136 from cryptography.hazmat.backends.openssl.backend import backend as ossl 

137 

138 _verify_rsa_parameters(public_exponent, key_size) 

139 return ossl.generate_rsa_private_key(public_exponent, key_size) 

140 

141 

142def _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 

149 if key_size < 512: 

150 raise ValueError("key_size must be at least 512-bits.") 

151 

152 

153def _check_private_key_components( 

154 p: int, 

155 q: int, 

156 private_exponent: int, 

157 dmp1: int, 

158 dmq1: int, 

159 iqmp: int, 

160 public_exponent: int, 

161 modulus: int, 

162) -> None: 

163 if modulus < 3: 

164 raise ValueError("modulus must be >= 3.") 

165 

166 if p >= modulus: 

167 raise ValueError("p must be < modulus.") 

168 

169 if q >= modulus: 

170 raise ValueError("q must be < modulus.") 

171 

172 if dmp1 >= modulus: 

173 raise ValueError("dmp1 must be < modulus.") 

174 

175 if dmq1 >= modulus: 

176 raise ValueError("dmq1 must be < modulus.") 

177 

178 if iqmp >= modulus: 

179 raise ValueError("iqmp must be < modulus.") 

180 

181 if private_exponent >= modulus: 

182 raise ValueError("private_exponent must be < modulus.") 

183 

184 if public_exponent < 3 or public_exponent >= modulus: 

185 raise ValueError("public_exponent must be >= 3 and < modulus.") 

186 

187 if public_exponent & 1 == 0: 

188 raise ValueError("public_exponent must be odd.") 

189 

190 if dmp1 & 1 == 0: 

191 raise ValueError("dmp1 must be odd.") 

192 

193 if dmq1 & 1 == 0: 

194 raise ValueError("dmq1 must be odd.") 

195 

196 if p * q != modulus: 

197 raise ValueError("p*q must equal modulus.") 

198 

199 

200def _check_public_key_components(e: int, n: int) -> None: 

201 if n < 3: 

202 raise ValueError("n must be >= 3.") 

203 

204 if e < 3 or e >= n: 

205 raise ValueError("e must be >= 3 and < n.") 

206 

207 if e & 1 == 0: 

208 raise ValueError("e must be odd.") 

209 

210 

211def _modinv(e: int, m: int) -> int: 

212 """ 

213 Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1 

214 """ 

215 x1, x2 = 1, 0 

216 a, b = e, m 

217 while b > 0: 

218 q, r = divmod(a, b) 

219 xn = x1 - q * x2 

220 a, b, x1, x2 = b, r, x2, xn 

221 return x1 % m 

222 

223 

224def rsa_crt_iqmp(p: int, q: int) -> int: 

225 """ 

226 Compute the CRT (q ** -1) % p value from RSA primes p and q. 

227 """ 

228 return _modinv(q, p) 

229 

230 

231def rsa_crt_dmp1(private_exponent: int, p: int) -> int: 

232 """ 

233 Compute the CRT private_exponent % (p - 1) value from the RSA 

234 private_exponent (d) and p. 

235 """ 

236 return private_exponent % (p - 1) 

237 

238 

239def rsa_crt_dmq1(private_exponent: int, q: int) -> int: 

240 """ 

241 Compute the CRT private_exponent % (q - 1) value from the RSA 

242 private_exponent (d) and q. 

243 """ 

244 return private_exponent % (q - 1) 

245 

246 

247# Controls the number of iterations rsa_recover_prime_factors will perform 

248# to obtain the prime factors. Each iteration increments by 2 so the actual 

249# maximum attempts is half this number. 

250_MAX_RECOVERY_ATTEMPTS = 1000 

251 

252 

253def rsa_recover_prime_factors( 

254 n: int, e: int, d: int 

255) -> typing.Tuple[int, int]: 

256 """ 

257 Compute factors p and q from the private exponent d. We assume that n has 

258 no more than two factors. This function is adapted from code in PyCrypto. 

259 """ 

260 # See 8.2.2(i) in Handbook of Applied Cryptography. 

261 ktot = d * e - 1 

262 # The quantity d*e-1 is a multiple of phi(n), even, 

263 # and can be represented as t*2^s. 

264 t = ktot 

265 while t % 2 == 0: 

266 t = t // 2 

267 # Cycle through all multiplicative inverses in Zn. 

268 # The algorithm is non-deterministic, but there is a 50% chance 

269 # any candidate a leads to successful factoring. 

270 # See "Digitalized Signatures and Public Key Functions as Intractable 

271 # as Factorization", M. Rabin, 1979 

272 spotted = False 

273 a = 2 

274 while not spotted and a < _MAX_RECOVERY_ATTEMPTS: 

275 k = t 

276 # Cycle through all values a^{t*2^i}=a^k 

277 while k < ktot: 

278 cand = pow(a, k, n) 

279 # Check if a^k is a non-trivial root of unity (mod n) 

280 if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: 

281 # We have found a number such that (cand-1)(cand+1)=0 (mod n). 

282 # Either of the terms divides n. 

283 p = gcd(cand + 1, n) 

284 spotted = True 

285 break 

286 k *= 2 

287 # This value was not any good... let's try another! 

288 a += 2 

289 if not spotted: 

290 raise ValueError("Unable to compute factors p and q from exponent d.") 

291 # Found ! 

292 q, r = divmod(n, p) 

293 assert r == 0 

294 p, q = sorted((p, q), reverse=True) 

295 return (p, q) 

296 

297 

298class RSAPrivateNumbers: 

299 def __init__( 

300 self, 

301 p: int, 

302 q: int, 

303 d: int, 

304 dmp1: int, 

305 dmq1: int, 

306 iqmp: int, 

307 public_numbers: RSAPublicNumbers, 

308 ): 

309 if ( 

310 not isinstance(p, int) 

311 or not isinstance(q, int) 

312 or not isinstance(d, int) 

313 or not isinstance(dmp1, int) 

314 or not isinstance(dmq1, int) 

315 or not isinstance(iqmp, int) 

316 ): 

317 raise TypeError( 

318 "RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must" 

319 " all be an integers." 

320 ) 

321 

322 if not isinstance(public_numbers, RSAPublicNumbers): 

323 raise TypeError( 

324 "RSAPrivateNumbers public_numbers must be an RSAPublicNumbers" 

325 " instance." 

326 ) 

327 

328 self._p = p 

329 self._q = q 

330 self._d = d 

331 self._dmp1 = dmp1 

332 self._dmq1 = dmq1 

333 self._iqmp = iqmp 

334 self._public_numbers = public_numbers 

335 

336 @property 

337 def p(self) -> int: 

338 return self._p 

339 

340 @property 

341 def q(self) -> int: 

342 return self._q 

343 

344 @property 

345 def d(self) -> int: 

346 return self._d 

347 

348 @property 

349 def dmp1(self) -> int: 

350 return self._dmp1 

351 

352 @property 

353 def dmq1(self) -> int: 

354 return self._dmq1 

355 

356 @property 

357 def iqmp(self) -> int: 

358 return self._iqmp 

359 

360 @property 

361 def public_numbers(self) -> RSAPublicNumbers: 

362 return self._public_numbers 

363 

364 def private_key( 

365 self, 

366 backend: typing.Any = None, 

367 *, 

368 unsafe_skip_rsa_key_validation: bool = False, 

369 ) -> RSAPrivateKey: 

370 from cryptography.hazmat.backends.openssl.backend import ( 

371 backend as ossl, 

372 ) 

373 

374 return ossl.load_rsa_private_numbers( 

375 self, unsafe_skip_rsa_key_validation 

376 ) 

377 

378 def __eq__(self, other: object) -> bool: 

379 if not isinstance(other, RSAPrivateNumbers): 

380 return NotImplemented 

381 

382 return ( 

383 self.p == other.p 

384 and self.q == other.q 

385 and self.d == other.d 

386 and self.dmp1 == other.dmp1 

387 and self.dmq1 == other.dmq1 

388 and self.iqmp == other.iqmp 

389 and self.public_numbers == other.public_numbers 

390 ) 

391 

392 def __hash__(self) -> int: 

393 return hash( 

394 ( 

395 self.p, 

396 self.q, 

397 self.d, 

398 self.dmp1, 

399 self.dmq1, 

400 self.iqmp, 

401 self.public_numbers, 

402 ) 

403 ) 

404 

405 

406class RSAPublicNumbers: 

407 def __init__(self, e: int, n: int): 

408 if not isinstance(e, int) or not isinstance(n, int): 

409 raise TypeError("RSAPublicNumbers arguments must be integers.") 

410 

411 self._e = e 

412 self._n = n 

413 

414 @property 

415 def e(self) -> int: 

416 return self._e 

417 

418 @property 

419 def n(self) -> int: 

420 return self._n 

421 

422 def public_key(self, backend: typing.Any = None) -> RSAPublicKey: 

423 from cryptography.hazmat.backends.openssl.backend import ( 

424 backend as ossl, 

425 ) 

426 

427 return ossl.load_rsa_public_numbers(self) 

428 

429 def __repr__(self) -> str: 

430 return "<RSAPublicNumbers(e={0.e}, n={0.n})>".format(self) 

431 

432 def __eq__(self, other: object) -> bool: 

433 if not isinstance(other, RSAPublicNumbers): 

434 return NotImplemented 

435 

436 return self.e == other.e and self.n == other.n 

437 

438 def __hash__(self) -> int: 

439 return hash((self.e, self.n))