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

179 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +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 ( 

13 utils as asym_utils, 

14) 

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 @abc.abstractproperty 

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 @abc.abstractproperty 

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(self, backend: typing.Any = None) -> RSAPrivateKey: 

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

359 backend as ossl, 

360 ) 

361 

362 return ossl.load_rsa_private_numbers(self) 

363 

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

365 if not isinstance(other, RSAPrivateNumbers): 

366 return NotImplemented 

367 

368 return ( 

369 self.p == other.p 

370 and self.q == other.q 

371 and self.d == other.d 

372 and self.dmp1 == other.dmp1 

373 and self.dmq1 == other.dmq1 

374 and self.iqmp == other.iqmp 

375 and self.public_numbers == other.public_numbers 

376 ) 

377 

378 def __hash__(self) -> int: 

379 return hash( 

380 ( 

381 self.p, 

382 self.q, 

383 self.d, 

384 self.dmp1, 

385 self.dmq1, 

386 self.iqmp, 

387 self.public_numbers, 

388 ) 

389 ) 

390 

391 

392class RSAPublicNumbers: 

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

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

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

396 

397 self._e = e 

398 self._n = n 

399 

400 @property 

401 def e(self) -> int: 

402 return self._e 

403 

404 @property 

405 def n(self) -> int: 

406 return self._n 

407 

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

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

410 backend as ossl, 

411 ) 

412 

413 return ossl.load_rsa_public_numbers(self) 

414 

415 def __repr__(self) -> str: 

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

417 

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

419 if not isinstance(other, RSAPublicNumbers): 

420 return NotImplemented 

421 

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

423 

424 def __hash__(self) -> int: 

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