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

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.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 

15 

16 

17class RSAPrivateKey(metaclass=abc.ABCMeta): 

18 @abc.abstractmethod 

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

20 """ 

21 Decrypts the provided ciphertext. 

22 """ 

23 

24 @property 

25 @abc.abstractmethod 

26 def key_size(self) -> int: 

27 """ 

28 The bit length of the public modulus. 

29 """ 

30 

31 @abc.abstractmethod 

32 def public_key(self) -> RSAPublicKey: 

33 """ 

34 The RSAPublicKey associated with this private key. 

35 """ 

36 

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 """ 

47 

48 @abc.abstractmethod 

49 def private_numbers(self) -> RSAPrivateNumbers: 

50 """ 

51 Returns an RSAPrivateNumbers. 

52 """ 

53 

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 """ 

64 

65 

66RSAPrivateKeyWithSerialization = RSAPrivateKey 

67RSAPrivateKey.register(rust_openssl.rsa.RSAPrivateKey) 

68 

69 

70class RSAPublicKey(metaclass=abc.ABCMeta): 

71 @abc.abstractmethod 

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

73 """ 

74 Encrypts the given plaintext. 

75 """ 

76 

77 @property 

78 @abc.abstractmethod 

79 def key_size(self) -> int: 

80 """ 

81 The bit length of the public modulus. 

82 """ 

83 

84 @abc.abstractmethod 

85 def public_numbers(self) -> RSAPublicNumbers: 

86 """ 

87 Returns an RSAPublicNumbers 

88 """ 

89 

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 """ 

99 

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 """ 

111 

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 """ 

122 

123 @abc.abstractmethod 

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

125 """ 

126 Checks equality. 

127 """ 

128 

129 

130RSAPublicKeyWithSerialization = RSAPublicKey 

131RSAPublicKey.register(rust_openssl.rsa.RSAPublicKey) 

132 

133 

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) 

141 

142 

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 ) 

149 

150 if key_size < 512: 

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

152 

153 

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.") 

166 

167 if p >= modulus: 

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

169 

170 if q >= modulus: 

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

172 

173 if dmp1 >= modulus: 

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

175 

176 if dmq1 >= modulus: 

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

178 

179 if iqmp >= modulus: 

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

181 

182 if private_exponent >= modulus: 

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

184 

185 if public_exponent < 3 or public_exponent >= modulus: 

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

187 

188 if public_exponent & 1 == 0: 

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

190 

191 if dmp1 & 1 == 0: 

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

193 

194 if dmq1 & 1 == 0: 

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

196 

197 if p * q != modulus: 

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

199 

200 

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

202 if n < 3: 

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

204 

205 if e < 3 or e >= n: 

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

207 

208 if e & 1 == 0: 

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

210 

211 

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 

223 

224 

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) 

230 

231 

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) 

238 

239 

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) 

246 

247 

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 

252 

253 

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) 

295 

296 

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 ) 

320 

321 if not isinstance(public_numbers, RSAPublicNumbers): 

322 raise TypeError( 

323 "RSAPrivateNumbers public_numbers must be an RSAPublicNumbers" 

324 " instance." 

325 ) 

326 

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 

334 

335 @property 

336 def p(self) -> int: 

337 return self._p 

338 

339 @property 

340 def q(self) -> int: 

341 return self._q 

342 

343 @property 

344 def d(self) -> int: 

345 return self._d 

346 

347 @property 

348 def dmp1(self) -> int: 

349 return self._dmp1 

350 

351 @property 

352 def dmq1(self) -> int: 

353 return self._dmq1 

354 

355 @property 

356 def iqmp(self) -> int: 

357 return self._iqmp 

358 

359 @property 

360 def public_numbers(self) -> RSAPublicNumbers: 

361 return self._public_numbers 

362 

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 ) 

382 

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

384 if not isinstance(other, RSAPrivateNumbers): 

385 return NotImplemented 

386 

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 ) 

396 

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 ) 

409 

410 

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.") 

415 

416 self._e = e 

417 self._n = n 

418 

419 @property 

420 def e(self) -> int: 

421 return self._e 

422 

423 @property 

424 def n(self) -> int: 

425 return self._n 

426 

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) 

430 

431 def __repr__(self) -> str: 

432 return f"<RSAPublicNumbers(e={self.e}, n={self.n})>" 

433 

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

435 if not isinstance(other, RSAPublicNumbers): 

436 return NotImplemented 

437 

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

439 

440 def __hash__(self) -> int: 

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