Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/rsa/key.py: 29%

255 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:40 +0000

1# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu> 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# https://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15"""RSA key generation code. 

16 

17Create new keys with the newkeys() function. It will give you a PublicKey and a 

18PrivateKey object. 

19 

20Loading and saving keys requires the pyasn1 module. This module is imported as 

21late as possible, such that other functionality will remain working in absence 

22of pyasn1. 

23 

24.. note:: 

25 

26 Storing public and private keys via the `pickle` module is possible. 

27 However, it is insecure to load a key from an untrusted source. 

28 The pickle module is not secure against erroneous or maliciously 

29 constructed data. Never unpickle data received from an untrusted 

30 or unauthenticated source. 

31 

32""" 

33 

34import threading 

35import typing 

36import warnings 

37 

38import rsa.prime 

39import rsa.pem 

40import rsa.common 

41import rsa.randnum 

42import rsa.core 

43 

44 

45DEFAULT_EXPONENT = 65537 

46 

47 

48T = typing.TypeVar("T", bound="AbstractKey") 

49 

50 

51class AbstractKey: 

52 """Abstract superclass for private and public keys.""" 

53 

54 __slots__ = ("n", "e", "blindfac", "blindfac_inverse", "mutex") 

55 

56 def __init__(self, n: int, e: int) -> None: 

57 self.n = n 

58 self.e = e 

59 

60 # These will be computed properly on the first call to blind(). 

61 self.blindfac = self.blindfac_inverse = -1 

62 

63 # Used to protect updates to the blinding factor in multi-threaded 

64 # environments. 

65 self.mutex = threading.Lock() 

66 

67 @classmethod 

68 def _load_pkcs1_pem(cls: typing.Type[T], keyfile: bytes) -> T: 

69 """Loads a key in PKCS#1 PEM format, implement in a subclass. 

70 

71 :param keyfile: contents of a PEM-encoded file that contains 

72 the public key. 

73 :type keyfile: bytes 

74 

75 :return: the loaded key 

76 :rtype: AbstractKey 

77 """ 

78 

79 @classmethod 

80 def _load_pkcs1_der(cls: typing.Type[T], keyfile: bytes) -> T: 

81 """Loads a key in PKCS#1 PEM format, implement in a subclass. 

82 

83 :param keyfile: contents of a DER-encoded file that contains 

84 the public key. 

85 :type keyfile: bytes 

86 

87 :return: the loaded key 

88 :rtype: AbstractKey 

89 """ 

90 

91 def _save_pkcs1_pem(self) -> bytes: 

92 """Saves the key in PKCS#1 PEM format, implement in a subclass. 

93 

94 :returns: the PEM-encoded key. 

95 :rtype: bytes 

96 """ 

97 

98 def _save_pkcs1_der(self) -> bytes: 

99 """Saves the key in PKCS#1 DER format, implement in a subclass. 

100 

101 :returns: the DER-encoded key. 

102 :rtype: bytes 

103 """ 

104 

105 @classmethod 

106 def load_pkcs1(cls: typing.Type[T], keyfile: bytes, format: str = "PEM") -> T: 

107 """Loads a key in PKCS#1 DER or PEM format. 

108 

109 :param keyfile: contents of a DER- or PEM-encoded file that contains 

110 the key. 

111 :type keyfile: bytes 

112 :param format: the format of the file to load; 'PEM' or 'DER' 

113 :type format: str 

114 

115 :return: the loaded key 

116 :rtype: AbstractKey 

117 """ 

118 

119 methods = { 

120 "PEM": cls._load_pkcs1_pem, 

121 "DER": cls._load_pkcs1_der, 

122 } 

123 

124 method = cls._assert_format_exists(format, methods) 

125 return method(keyfile) 

126 

127 @staticmethod 

128 def _assert_format_exists( 

129 file_format: str, methods: typing.Mapping[str, typing.Callable] 

130 ) -> typing.Callable: 

131 """Checks whether the given file format exists in 'methods'.""" 

132 

133 try: 

134 return methods[file_format] 

135 except KeyError as ex: 

136 formats = ", ".join(sorted(methods.keys())) 

137 raise ValueError( 

138 "Unsupported format: %r, try one of %s" % (file_format, formats) 

139 ) from ex 

140 

141 def save_pkcs1(self, format: str = "PEM") -> bytes: 

142 """Saves the key in PKCS#1 DER or PEM format. 

143 

144 :param format: the format to save; 'PEM' or 'DER' 

145 :type format: str 

146 :returns: the DER- or PEM-encoded key. 

147 :rtype: bytes 

148 """ 

149 

150 methods = { 

151 "PEM": self._save_pkcs1_pem, 

152 "DER": self._save_pkcs1_der, 

153 } 

154 

155 method = self._assert_format_exists(format, methods) 

156 return method() 

157 

158 def blind(self, message: int) -> typing.Tuple[int, int]: 

159 """Performs blinding on the message. 

160 

161 :param message: the message, as integer, to blind. 

162 :param r: the random number to blind with. 

163 :return: tuple (the blinded message, the inverse of the used blinding factor) 

164 

165 The blinding is such that message = unblind(decrypt(blind(encrypt(message))). 

166 

167 See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 

168 """ 

169 blindfac, blindfac_inverse = self._update_blinding_factor() 

170 blinded = (message * pow(blindfac, self.e, self.n)) % self.n 

171 return blinded, blindfac_inverse 

172 

173 def unblind(self, blinded: int, blindfac_inverse: int) -> int: 

174 """Performs blinding on the message using random number 'blindfac_inverse'. 

175 

176 :param blinded: the blinded message, as integer, to unblind. 

177 :param blindfac: the factor to unblind with. 

178 :return: the original message. 

179 

180 The blinding is such that message = unblind(decrypt(blind(encrypt(message))). 

181 

182 See https://en.wikipedia.org/wiki/Blinding_%28cryptography%29 

183 """ 

184 return (blindfac_inverse * blinded) % self.n 

185 

186 def _initial_blinding_factor(self) -> int: 

187 for _ in range(1000): 

188 blind_r = rsa.randnum.randint(self.n - 1) 

189 if rsa.prime.are_relatively_prime(self.n, blind_r): 

190 return blind_r 

191 raise RuntimeError("unable to find blinding factor") 

192 

193 def _update_blinding_factor(self) -> typing.Tuple[int, int]: 

194 """Update blinding factors. 

195 

196 Computing a blinding factor is expensive, so instead this function 

197 does this once, then updates the blinding factor as per section 9 

198 of 'A Timing Attack against RSA with the Chinese Remainder Theorem' 

199 by Werner Schindler. 

200 See https://tls.mbed.org/public/WSchindler-RSA_Timing_Attack.pdf 

201 

202 :return: the new blinding factor and its inverse. 

203 """ 

204 

205 with self.mutex: 

206 if self.blindfac < 0: 

207 # Compute initial blinding factor, which is rather slow to do. 

208 self.blindfac = self._initial_blinding_factor() 

209 self.blindfac_inverse = rsa.common.inverse(self.blindfac, self.n) 

210 else: 

211 # Reuse previous blinding factor. 

212 self.blindfac = pow(self.blindfac, 2, self.n) 

213 self.blindfac_inverse = pow(self.blindfac_inverse, 2, self.n) 

214 

215 return self.blindfac, self.blindfac_inverse 

216 

217 

218class PublicKey(AbstractKey): 

219 """Represents a public RSA key. 

220 

221 This key is also known as the 'encryption key'. It contains the 'n' and 'e' 

222 values. 

223 

224 Supports attributes as well as dictionary-like access. Attribute access is 

225 faster, though. 

226 

227 >>> PublicKey(5, 3) 

228 PublicKey(5, 3) 

229 

230 >>> key = PublicKey(5, 3) 

231 >>> key.n 

232 5 

233 >>> key['n'] 

234 5 

235 >>> key.e 

236 3 

237 >>> key['e'] 

238 3 

239 

240 """ 

241 

242 __slots__ = () 

243 

244 def __getitem__(self, key: str) -> int: 

245 return getattr(self, key) 

246 

247 def __repr__(self) -> str: 

248 return "PublicKey(%i, %i)" % (self.n, self.e) 

249 

250 def __getstate__(self) -> typing.Tuple[int, int]: 

251 """Returns the key as tuple for pickling.""" 

252 return self.n, self.e 

253 

254 def __setstate__(self, state: typing.Tuple[int, int]) -> None: 

255 """Sets the key from tuple.""" 

256 self.n, self.e = state 

257 AbstractKey.__init__(self, self.n, self.e) 

258 

259 def __eq__(self, other: typing.Any) -> bool: 

260 if other is None: 

261 return False 

262 

263 if not isinstance(other, PublicKey): 

264 return False 

265 

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

267 

268 def __ne__(self, other: typing.Any) -> bool: 

269 return not (self == other) 

270 

271 def __hash__(self) -> int: 

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

273 

274 @classmethod 

275 def _load_pkcs1_der(cls, keyfile: bytes) -> "PublicKey": 

276 """Loads a key in PKCS#1 DER format. 

277 

278 :param keyfile: contents of a DER-encoded file that contains the public 

279 key. 

280 :return: a PublicKey object 

281 

282 First let's construct a DER encoded key: 

283 

284 >>> import base64 

285 >>> b64der = 'MAwCBQCNGmYtAgMBAAE=' 

286 >>> der = base64.standard_b64decode(b64der) 

287 

288 This loads the file: 

289 

290 >>> PublicKey._load_pkcs1_der(der) 

291 PublicKey(2367317549, 65537) 

292 

293 """ 

294 

295 from pyasn1.codec.der import decoder 

296 from rsa.asn1 import AsnPubKey 

297 

298 (priv, _) = decoder.decode(keyfile, asn1Spec=AsnPubKey()) 

299 return cls(n=int(priv["modulus"]), e=int(priv["publicExponent"])) 

300 

301 def _save_pkcs1_der(self) -> bytes: 

302 """Saves the public key in PKCS#1 DER format. 

303 

304 :returns: the DER-encoded public key. 

305 :rtype: bytes 

306 """ 

307 

308 from pyasn1.codec.der import encoder 

309 from rsa.asn1 import AsnPubKey 

310 

311 # Create the ASN object 

312 asn_key = AsnPubKey() 

313 asn_key.setComponentByName("modulus", self.n) 

314 asn_key.setComponentByName("publicExponent", self.e) 

315 

316 return encoder.encode(asn_key) 

317 

318 @classmethod 

319 def _load_pkcs1_pem(cls, keyfile: bytes) -> "PublicKey": 

320 """Loads a PKCS#1 PEM-encoded public key file. 

321 

322 The contents of the file before the "-----BEGIN RSA PUBLIC KEY-----" and 

323 after the "-----END RSA PUBLIC KEY-----" lines is ignored. 

324 

325 :param keyfile: contents of a PEM-encoded file that contains the public 

326 key. 

327 :return: a PublicKey object 

328 """ 

329 

330 der = rsa.pem.load_pem(keyfile, "RSA PUBLIC KEY") 

331 return cls._load_pkcs1_der(der) 

332 

333 def _save_pkcs1_pem(self) -> bytes: 

334 """Saves a PKCS#1 PEM-encoded public key file. 

335 

336 :return: contents of a PEM-encoded file that contains the public key. 

337 :rtype: bytes 

338 """ 

339 

340 der = self._save_pkcs1_der() 

341 return rsa.pem.save_pem(der, "RSA PUBLIC KEY") 

342 

343 @classmethod 

344 def load_pkcs1_openssl_pem(cls, keyfile: bytes) -> "PublicKey": 

345 """Loads a PKCS#1.5 PEM-encoded public key file from OpenSSL. 

346 

347 These files can be recognised in that they start with BEGIN PUBLIC KEY 

348 rather than BEGIN RSA PUBLIC KEY. 

349 

350 The contents of the file before the "-----BEGIN PUBLIC KEY-----" and 

351 after the "-----END PUBLIC KEY-----" lines is ignored. 

352 

353 :param keyfile: contents of a PEM-encoded file that contains the public 

354 key, from OpenSSL. 

355 :type keyfile: bytes 

356 :return: a PublicKey object 

357 """ 

358 

359 der = rsa.pem.load_pem(keyfile, "PUBLIC KEY") 

360 return cls.load_pkcs1_openssl_der(der) 

361 

362 @classmethod 

363 def load_pkcs1_openssl_der(cls, keyfile: bytes) -> "PublicKey": 

364 """Loads a PKCS#1 DER-encoded public key file from OpenSSL. 

365 

366 :param keyfile: contents of a DER-encoded file that contains the public 

367 key, from OpenSSL. 

368 :return: a PublicKey object 

369 """ 

370 

371 from rsa.asn1 import OpenSSLPubKey 

372 from pyasn1.codec.der import decoder 

373 from pyasn1.type import univ 

374 

375 (keyinfo, _) = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey()) 

376 

377 if keyinfo["header"]["oid"] != univ.ObjectIdentifier("1.2.840.113549.1.1.1"): 

378 raise TypeError("This is not a DER-encoded OpenSSL-compatible public key") 

379 

380 return cls._load_pkcs1_der(keyinfo["key"][1:]) 

381 

382 

383class PrivateKey(AbstractKey): 

384 """Represents a private RSA key. 

385 

386 This key is also known as the 'decryption key'. It contains the 'n', 'e', 

387 'd', 'p', 'q' and other values. 

388 

389 Supports attributes as well as dictionary-like access. Attribute access is 

390 faster, though. 

391 

392 >>> PrivateKey(3247, 65537, 833, 191, 17) 

393 PrivateKey(3247, 65537, 833, 191, 17) 

394 

395 exp1, exp2 and coef will be calculated: 

396 

397 >>> pk = PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) 

398 >>> pk.exp1 

399 55063 

400 >>> pk.exp2 

401 10095 

402 >>> pk.coef 

403 50797 

404 

405 """ 

406 

407 __slots__ = ("d", "p", "q", "exp1", "exp2", "coef") 

408 

409 def __init__(self, n: int, e: int, d: int, p: int, q: int) -> None: 

410 AbstractKey.__init__(self, n, e) 

411 self.d = d 

412 self.p = p 

413 self.q = q 

414 

415 # Calculate exponents and coefficient. 

416 self.exp1 = int(d % (p - 1)) 

417 self.exp2 = int(d % (q - 1)) 

418 self.coef = rsa.common.inverse(q, p) 

419 

420 def __getitem__(self, key: str) -> int: 

421 return getattr(self, key) 

422 

423 def __repr__(self) -> str: 

424 return "PrivateKey(%i, %i, %i, %i, %i)" % ( 

425 self.n, 

426 self.e, 

427 self.d, 

428 self.p, 

429 self.q, 

430 ) 

431 

432 def __getstate__(self) -> typing.Tuple[int, int, int, int, int, int, int, int]: 

433 """Returns the key as tuple for pickling.""" 

434 return self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef 

435 

436 def __setstate__(self, state: typing.Tuple[int, int, int, int, int, int, int, int]) -> None: 

437 """Sets the key from tuple.""" 

438 self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef = state 

439 AbstractKey.__init__(self, self.n, self.e) 

440 

441 def __eq__(self, other: typing.Any) -> bool: 

442 if other is None: 

443 return False 

444 

445 if not isinstance(other, PrivateKey): 

446 return False 

447 

448 return ( 

449 self.n == other.n 

450 and self.e == other.e 

451 and self.d == other.d 

452 and self.p == other.p 

453 and self.q == other.q 

454 and self.exp1 == other.exp1 

455 and self.exp2 == other.exp2 

456 and self.coef == other.coef 

457 ) 

458 

459 def __ne__(self, other: typing.Any) -> bool: 

460 return not (self == other) 

461 

462 def __hash__(self) -> int: 

463 return hash((self.n, self.e, self.d, self.p, self.q, self.exp1, self.exp2, self.coef)) 

464 

465 def blinded_decrypt(self, encrypted: int) -> int: 

466 """Decrypts the message using blinding to prevent side-channel attacks. 

467 

468 :param encrypted: the encrypted message 

469 :type encrypted: int 

470 

471 :returns: the decrypted message 

472 :rtype: int 

473 """ 

474 

475 # Blinding and un-blinding should be using the same factor 

476 blinded, blindfac_inverse = self.blind(encrypted) 

477 

478 # Instead of using the core functionality, use the Chinese Remainder 

479 # Theorem and be 2-4x faster. This the same as: 

480 # 

481 # decrypted = rsa.core.decrypt_int(blinded, self.d, self.n) 

482 s1 = pow(blinded, self.exp1, self.p) 

483 s2 = pow(blinded, self.exp2, self.q) 

484 h = ((s1 - s2) * self.coef) % self.p 

485 decrypted = s2 + self.q * h 

486 

487 return self.unblind(decrypted, blindfac_inverse) 

488 

489 def blinded_encrypt(self, message: int) -> int: 

490 """Encrypts the message using blinding to prevent side-channel attacks. 

491 

492 :param message: the message to encrypt 

493 :type message: int 

494 

495 :returns: the encrypted message 

496 :rtype: int 

497 """ 

498 

499 blinded, blindfac_inverse = self.blind(message) 

500 encrypted = rsa.core.encrypt_int(blinded, self.d, self.n) 

501 return self.unblind(encrypted, blindfac_inverse) 

502 

503 @classmethod 

504 def _load_pkcs1_der(cls, keyfile: bytes) -> "PrivateKey": 

505 """Loads a key in PKCS#1 DER format. 

506 

507 :param keyfile: contents of a DER-encoded file that contains the private 

508 key. 

509 :type keyfile: bytes 

510 :return: a PrivateKey object 

511 

512 First let's construct a DER encoded key: 

513 

514 >>> import base64 

515 >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt' 

516 >>> der = base64.standard_b64decode(b64der) 

517 

518 This loads the file: 

519 

520 >>> PrivateKey._load_pkcs1_der(der) 

521 PrivateKey(3727264081, 65537, 3349121513, 65063, 57287) 

522 

523 """ 

524 

525 from pyasn1.codec.der import decoder 

526 

527 (priv, _) = decoder.decode(keyfile) 

528 

529 # ASN.1 contents of DER encoded private key: 

530 # 

531 # RSAPrivateKey ::= SEQUENCE { 

532 # version Version, 

533 # modulus INTEGER, -- n 

534 # publicExponent INTEGER, -- e 

535 # privateExponent INTEGER, -- d 

536 # prime1 INTEGER, -- p 

537 # prime2 INTEGER, -- q 

538 # exponent1 INTEGER, -- d mod (p-1) 

539 # exponent2 INTEGER, -- d mod (q-1) 

540 # coefficient INTEGER, -- (inverse of q) mod p 

541 # otherPrimeInfos OtherPrimeInfos OPTIONAL 

542 # } 

543 

544 if priv[0] != 0: 

545 raise ValueError("Unable to read this file, version %s != 0" % priv[0]) 

546 

547 as_ints = map(int, priv[1:6]) 

548 key = cls(*as_ints) 

549 

550 exp1, exp2, coef = map(int, priv[6:9]) 

551 

552 if (key.exp1, key.exp2, key.coef) != (exp1, exp2, coef): 

553 warnings.warn( 

554 "You have provided a malformed keyfile. Either the exponents " 

555 "or the coefficient are incorrect. Using the correct values " 

556 "instead.", 

557 UserWarning, 

558 ) 

559 

560 return key 

561 

562 def _save_pkcs1_der(self) -> bytes: 

563 """Saves the private key in PKCS#1 DER format. 

564 

565 :returns: the DER-encoded private key. 

566 :rtype: bytes 

567 """ 

568 

569 from pyasn1.type import univ, namedtype 

570 from pyasn1.codec.der import encoder 

571 

572 class AsnPrivKey(univ.Sequence): 

573 componentType = namedtype.NamedTypes( 

574 namedtype.NamedType("version", univ.Integer()), 

575 namedtype.NamedType("modulus", univ.Integer()), 

576 namedtype.NamedType("publicExponent", univ.Integer()), 

577 namedtype.NamedType("privateExponent", univ.Integer()), 

578 namedtype.NamedType("prime1", univ.Integer()), 

579 namedtype.NamedType("prime2", univ.Integer()), 

580 namedtype.NamedType("exponent1", univ.Integer()), 

581 namedtype.NamedType("exponent2", univ.Integer()), 

582 namedtype.NamedType("coefficient", univ.Integer()), 

583 ) 

584 

585 # Create the ASN object 

586 asn_key = AsnPrivKey() 

587 asn_key.setComponentByName("version", 0) 

588 asn_key.setComponentByName("modulus", self.n) 

589 asn_key.setComponentByName("publicExponent", self.e) 

590 asn_key.setComponentByName("privateExponent", self.d) 

591 asn_key.setComponentByName("prime1", self.p) 

592 asn_key.setComponentByName("prime2", self.q) 

593 asn_key.setComponentByName("exponent1", self.exp1) 

594 asn_key.setComponentByName("exponent2", self.exp2) 

595 asn_key.setComponentByName("coefficient", self.coef) 

596 

597 return encoder.encode(asn_key) 

598 

599 @classmethod 

600 def _load_pkcs1_pem(cls, keyfile: bytes) -> "PrivateKey": 

601 """Loads a PKCS#1 PEM-encoded private key file. 

602 

603 The contents of the file before the "-----BEGIN RSA PRIVATE KEY-----" and 

604 after the "-----END RSA PRIVATE KEY-----" lines is ignored. 

605 

606 :param keyfile: contents of a PEM-encoded file that contains the private 

607 key. 

608 :type keyfile: bytes 

609 :return: a PrivateKey object 

610 """ 

611 

612 der = rsa.pem.load_pem(keyfile, b"RSA PRIVATE KEY") 

613 return cls._load_pkcs1_der(der) 

614 

615 def _save_pkcs1_pem(self) -> bytes: 

616 """Saves a PKCS#1 PEM-encoded private key file. 

617 

618 :return: contents of a PEM-encoded file that contains the private key. 

619 :rtype: bytes 

620 """ 

621 

622 der = self._save_pkcs1_der() 

623 return rsa.pem.save_pem(der, b"RSA PRIVATE KEY") 

624 

625 

626def find_p_q( 

627 nbits: int, 

628 getprime_func: typing.Callable[[int], int] = rsa.prime.getprime, 

629 accurate: bool = True, 

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

631 """Returns a tuple of two different primes of nbits bits each. 

632 

633 The resulting p * q has exactly 2 * nbits bits, and the returned p and q 

634 will not be equal. 

635 

636 :param nbits: the number of bits in each of p and q. 

637 :param getprime_func: the getprime function, defaults to 

638 :py:func:`rsa.prime.getprime`. 

639 

640 *Introduced in Python-RSA 3.1* 

641 

642 :param accurate: whether to enable accurate mode or not. 

643 :returns: (p, q), where p > q 

644 

645 >>> (p, q) = find_p_q(128) 

646 >>> from rsa import common 

647 >>> common.bit_size(p * q) 

648 256 

649 

650 When not in accurate mode, the number of bits can be slightly less 

651 

652 >>> (p, q) = find_p_q(128, accurate=False) 

653 >>> from rsa import common 

654 >>> common.bit_size(p * q) <= 256 

655 True 

656 >>> common.bit_size(p * q) > 240 

657 True 

658 

659 """ 

660 

661 total_bits = nbits * 2 

662 

663 # Make sure that p and q aren't too close or the factoring programs can 

664 # factor n. 

665 shift = nbits // 16 

666 pbits = nbits + shift 

667 qbits = nbits - shift 

668 

669 # Choose the two initial primes 

670 p = getprime_func(pbits) 

671 q = getprime_func(qbits) 

672 

673 def is_acceptable(p: int, q: int) -> bool: 

674 """Returns True iff p and q are acceptable: 

675 

676 - p and q differ 

677 - (p * q) has the right nr of bits (when accurate=True) 

678 """ 

679 

680 if p == q: 

681 return False 

682 

683 if not accurate: 

684 return True 

685 

686 # Make sure we have just the right amount of bits 

687 found_size = rsa.common.bit_size(p * q) 

688 return total_bits == found_size 

689 

690 # Keep choosing other primes until they match our requirements. 

691 change_p = False 

692 while not is_acceptable(p, q): 

693 # Change p on one iteration and q on the other 

694 if change_p: 

695 p = getprime_func(pbits) 

696 else: 

697 q = getprime_func(qbits) 

698 

699 change_p = not change_p 

700 

701 # We want p > q as described on 

702 # http://www.di-mgt.com.au/rsa_alg.html#crt 

703 return max(p, q), min(p, q) 

704 

705 

706def calculate_keys_custom_exponent(p: int, q: int, exponent: int) -> typing.Tuple[int, int]: 

707 """Calculates an encryption and a decryption key given p, q and an exponent, 

708 and returns them as a tuple (e, d) 

709 

710 :param p: the first large prime 

711 :param q: the second large prime 

712 :param exponent: the exponent for the key; only change this if you know 

713 what you're doing, as the exponent influences how difficult your 

714 private key can be cracked. A very common choice for e is 65537. 

715 :type exponent: int 

716 

717 """ 

718 

719 phi_n = (p - 1) * (q - 1) 

720 

721 try: 

722 d = rsa.common.inverse(exponent, phi_n) 

723 except rsa.common.NotRelativePrimeError as ex: 

724 raise rsa.common.NotRelativePrimeError( 

725 exponent, 

726 phi_n, 

727 ex.d, 

728 msg="e (%d) and phi_n (%d) are not relatively prime (divider=%i)" 

729 % (exponent, phi_n, ex.d), 

730 ) from ex 

731 

732 if (exponent * d) % phi_n != 1: 

733 raise ValueError( 

734 "e (%d) and d (%d) are not mult. inv. modulo " "phi_n (%d)" % (exponent, d, phi_n) 

735 ) 

736 

737 return exponent, d 

738 

739 

740def calculate_keys(p: int, q: int) -> typing.Tuple[int, int]: 

741 """Calculates an encryption and a decryption key given p and q, and 

742 returns them as a tuple (e, d) 

743 

744 :param p: the first large prime 

745 :param q: the second large prime 

746 

747 :return: tuple (e, d) with the encryption and decryption exponents. 

748 """ 

749 

750 return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT) 

751 

752 

753def gen_keys( 

754 nbits: int, 

755 getprime_func: typing.Callable[[int], int], 

756 accurate: bool = True, 

757 exponent: int = DEFAULT_EXPONENT, 

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

759 """Generate RSA keys of nbits bits. Returns (p, q, e, d). 

760 

761 Note: this can take a long time, depending on the key size. 

762 

763 :param nbits: the total number of bits in ``p`` and ``q``. Both ``p`` and 

764 ``q`` will use ``nbits/2`` bits. 

765 :param getprime_func: either :py:func:`rsa.prime.getprime` or a function 

766 with similar signature. 

767 :param exponent: the exponent for the key; only change this if you know 

768 what you're doing, as the exponent influences how difficult your 

769 private key can be cracked. A very common choice for e is 65537. 

770 :type exponent: int 

771 """ 

772 

773 # Regenerate p and q values, until calculate_keys doesn't raise a 

774 # ValueError. 

775 while True: 

776 (p, q) = find_p_q(nbits // 2, getprime_func, accurate) 

777 try: 

778 (e, d) = calculate_keys_custom_exponent(p, q, exponent=exponent) 

779 break 

780 except ValueError: 

781 pass 

782 

783 return p, q, e, d 

784 

785 

786def newkeys( 

787 nbits: int, 

788 accurate: bool = True, 

789 poolsize: int = 1, 

790 exponent: int = DEFAULT_EXPONENT, 

791) -> typing.Tuple[PublicKey, PrivateKey]: 

792 """Generates public and private keys, and returns them as (pub, priv). 

793 

794 The public key is also known as the 'encryption key', and is a 

795 :py:class:`rsa.PublicKey` object. The private key is also known as the 

796 'decryption key' and is a :py:class:`rsa.PrivateKey` object. 

797 

798 :param nbits: the number of bits required to store ``n = p*q``. 

799 :param accurate: when True, ``n`` will have exactly the number of bits you 

800 asked for. However, this makes key generation much slower. When False, 

801 `n`` may have slightly less bits. 

802 :param poolsize: the number of processes to use to generate the prime 

803 numbers. If set to a number > 1, a parallel algorithm will be used. 

804 This requires Python 2.6 or newer. 

805 :param exponent: the exponent for the key; only change this if you know 

806 what you're doing, as the exponent influences how difficult your 

807 private key can be cracked. A very common choice for e is 65537. 

808 :type exponent: int 

809 

810 :returns: a tuple (:py:class:`rsa.PublicKey`, :py:class:`rsa.PrivateKey`) 

811 

812 The ``poolsize`` parameter was added in *Python-RSA 3.1* and requires 

813 Python 2.6 or newer. 

814 

815 """ 

816 

817 if nbits < 16: 

818 raise ValueError("Key too small") 

819 

820 if poolsize < 1: 

821 raise ValueError("Pool size (%i) should be >= 1" % poolsize) 

822 

823 # Determine which getprime function to use 

824 if poolsize > 1: 

825 from rsa import parallel 

826 

827 def getprime_func(nbits: int) -> int: 

828 return parallel.getprime(nbits, poolsize=poolsize) 

829 

830 else: 

831 getprime_func = rsa.prime.getprime 

832 

833 # Generate the key components 

834 (p, q, e, d) = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent) 

835 

836 # Create the key objects 

837 n = p * q 

838 

839 return (PublicKey(n, e), PrivateKey(n, e, d, p, q)) 

840 

841 

842__all__ = ["PublicKey", "PrivateKey", "newkeys"] 

843 

844if __name__ == "__main__": 

845 import doctest 

846 

847 try: 

848 for count in range(100): 

849 (failures, tests) = doctest.testmod() 

850 if failures: 

851 break 

852 

853 if (count % 10 == 0 and count) or count == 1: 

854 print("%i times" % count) 

855 except KeyboardInterrupt: 

856 print("Aborted") 

857 else: 

858 print("Doctests done")