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

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 

5 

6import abc 

7import typing 

8from math import gcd 

9 

10from cryptography.hazmat.primitives import _serialization, hashes 

11from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding 

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

13 

14 

15class RSAPrivateKey(metaclass=abc.ABCMeta): 

16 @abc.abstractmethod 

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

18 """ 

19 Decrypts the provided ciphertext. 

20 """ 

21 

22 @property 

23 @abc.abstractmethod 

24 def key_size(self) -> int: 

25 """ 

26 The bit length of the public modulus. 

27 """ 

28 

29 @abc.abstractmethod 

30 def public_key(self) -> "RSAPublicKey": 

31 """ 

32 The RSAPublicKey associated with this private key. 

33 """ 

34 

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

45 

46 @abc.abstractmethod 

47 def private_numbers(self) -> "RSAPrivateNumbers": 

48 """ 

49 Returns an RSAPrivateNumbers. 

50 """ 

51 

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

62 

63 

64RSAPrivateKeyWithSerialization = RSAPrivateKey 

65 

66 

67class RSAPublicKey(metaclass=abc.ABCMeta): 

68 @abc.abstractmethod 

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

70 """ 

71 Encrypts the given plaintext. 

72 """ 

73 

74 @property 

75 @abc.abstractmethod 

76 def key_size(self) -> int: 

77 """ 

78 The bit length of the public modulus. 

79 """ 

80 

81 @abc.abstractmethod 

82 def public_numbers(self) -> "RSAPublicNumbers": 

83 """ 

84 Returns an RSAPublicNumbers 

85 """ 

86 

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

96 

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

108 

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

119 

120 

121RSAPublicKeyWithSerialization = RSAPublicKey 

122 

123 

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 

130 

131 _verify_rsa_parameters(public_exponent, key_size) 

132 return ossl.generate_rsa_private_key(public_exponent, key_size) 

133 

134 

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 ) 

141 

142 if key_size < 512: 

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

144 

145 

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

158 

159 if p >= modulus: 

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

161 

162 if q >= modulus: 

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

164 

165 if dmp1 >= modulus: 

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

167 

168 if dmq1 >= modulus: 

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

170 

171 if iqmp >= modulus: 

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

173 

174 if private_exponent >= modulus: 

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

176 

177 if public_exponent < 3 or public_exponent >= modulus: 

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

179 

180 if public_exponent & 1 == 0: 

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

182 

183 if dmp1 & 1 == 0: 

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

185 

186 if dmq1 & 1 == 0: 

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

188 

189 if p * q != modulus: 

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

191 

192 

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

194 if n < 3: 

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

196 

197 if e < 3 or e >= n: 

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

199 

200 if e & 1 == 0: 

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

202 

203 

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 

215 

216 

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) 

222 

223 

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) 

230 

231 

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) 

238 

239 

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 

244 

245 

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) 

289 

290 

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 ) 

314 

315 if not isinstance(public_numbers, RSAPublicNumbers): 

316 raise TypeError( 

317 "RSAPrivateNumbers public_numbers must be an RSAPublicNumbers" 

318 " instance." 

319 ) 

320 

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 

328 

329 @property 

330 def p(self) -> int: 

331 return self._p 

332 

333 @property 

334 def q(self) -> int: 

335 return self._q 

336 

337 @property 

338 def d(self) -> int: 

339 return self._d 

340 

341 @property 

342 def dmp1(self) -> int: 

343 return self._dmp1 

344 

345 @property 

346 def dmq1(self) -> int: 

347 return self._dmq1 

348 

349 @property 

350 def iqmp(self) -> int: 

351 return self._iqmp 

352 

353 @property 

354 def public_numbers(self) -> "RSAPublicNumbers": 

355 return self._public_numbers 

356 

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 ) 

366 

367 return ossl.load_rsa_private_numbers( 

368 self, unsafe_skip_rsa_key_validation 

369 ) 

370 

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

372 if not isinstance(other, RSAPrivateNumbers): 

373 return NotImplemented 

374 

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 ) 

384 

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 ) 

397 

398 

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

403 

404 self._e = e 

405 self._n = n 

406 

407 @property 

408 def e(self) -> int: 

409 return self._e 

410 

411 @property 

412 def n(self) -> int: 

413 return self._n 

414 

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

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

417 backend as ossl, 

418 ) 

419 

420 return ossl.load_rsa_public_numbers(self) 

421 

422 def __repr__(self) -> str: 

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

424 

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

426 if not isinstance(other, RSAPublicNumbers): 

427 return NotImplemented 

428 

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

430 

431 def __hash__(self) -> int: 

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