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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

298 statements  

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 abc 

35import math 

36import threading 

37import typing 

38import warnings 

39import itertools 

40 

41import rsa.prime 

42import rsa.pem 

43import rsa.common 

44import rsa.randnum 

45import rsa.core 

46 

47 

48DEFAULT_EXPONENT = 65537 

49 

50 

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

52 

53 

54class AbstractKey(metaclass=abc.ABCMeta): 

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

56 

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

58 

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

60 self.n = n 

61 self.e = e 

62 

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

64 self.blindfac = self.blindfac_inverse = -1 

65 

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

67 # environments. 

68 self.mutex = threading.Lock() 

69 

70 @classmethod 

71 @abc.abstractmethod 

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

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

74 

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

76 the public key. 

77 :type keyfile: bytes 

78 

79 :return: the loaded key 

80 :rtype: AbstractKey 

81 """ 

82 

83 @classmethod 

84 @abc.abstractmethod 

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

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

87 

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

89 the public key. 

90 :type keyfile: bytes 

91 

92 :return: the loaded key 

93 :rtype: AbstractKey 

94 """ 

95 

96 @abc.abstractmethod 

97 def _save_pkcs1_pem(self) -> bytes: 

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

99 

100 :returns: the PEM-encoded key. 

101 :rtype: bytes 

102 """ 

103 

104 @abc.abstractmethod 

105 def _save_pkcs1_der(self) -> bytes: 

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

107 

108 :returns: the DER-encoded key. 

109 :rtype: bytes 

110 """ 

111 

112 @classmethod 

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

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

115 

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

117 the key. 

118 :type keyfile: bytes 

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

120 :type format: str 

121 

122 :return: the loaded key 

123 :rtype: AbstractKey 

124 """ 

125 

126 methods = { 

127 "PEM": cls._load_pkcs1_pem, 

128 "DER": cls._load_pkcs1_der, 

129 } 

130 

131 method = cls._assert_format_exists(format, methods) 

132 return method(keyfile) 

133 

134 @staticmethod 

135 def _assert_format_exists( 

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

137 ) -> typing.Callable: 

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

139 

140 try: 

141 return methods[file_format] 

142 except KeyError as ex: 

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

144 raise ValueError( 

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

146 ) from ex 

147 

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

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

150 

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

152 :type format: str 

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

154 :rtype: bytes 

155 """ 

156 

157 methods = { 

158 "PEM": self._save_pkcs1_pem, 

159 "DER": self._save_pkcs1_der, 

160 } 

161 

162 method = self._assert_format_exists(format, methods) 

163 return method() 

164 

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

166 """Performs blinding on the message. 

167 

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

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

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

171 

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

173 

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

175 """ 

176 blindfac, blindfac_inverse = self._update_blinding_factor() 

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

178 return blinded, blindfac_inverse 

179 

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

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

182 

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

184 :param blindfac: the factor to unblind with. 

185 :return: the original message. 

186 

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

188 

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

190 """ 

191 return (blindfac_inverse * blinded) % self.n 

192 

193 def _initial_blinding_factor(self) -> int: 

194 for _ in range(1000): 

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

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

197 return blind_r 

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

199 

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

201 """Update blinding factors. 

202 

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

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

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

206 by Werner Schindler. 

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

208 

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

210 """ 

211 

212 with self.mutex: 

213 if self.blindfac < 0: 

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

215 self.blindfac = self._initial_blinding_factor() 

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

217 else: 

218 # Reuse previous blinding factor. 

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

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

221 

222 return self.blindfac, self.blindfac_inverse 

223 

224 

225class PublicKey(AbstractKey): 

226 """Represents a public RSA key. 

227 

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

229 values. 

230 

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

232 faster, though. 

233 

234 >>> PublicKey(5, 3) 

235 PublicKey(5, 3) 

236 

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

238 >>> key.n 

239 5 

240 >>> key['n'] 

241 5 

242 >>> key.e 

243 3 

244 >>> key['e'] 

245 3 

246 

247 """ 

248 

249 __slots__ = () 

250 

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

252 return getattr(self, key) 

253 

254 def __repr__(self) -> str: 

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

256 

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

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

259 return self.n, self.e 

260 

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

262 """Sets the key from tuple.""" 

263 self.n, self.e = state 

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

265 

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

267 if other is None: 

268 return False 

269 

270 if not isinstance(other, PublicKey): 

271 return False 

272 

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

274 

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

276 return not (self == other) 

277 

278 def __hash__(self) -> int: 

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

280 

281 @classmethod 

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

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

284 

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

286 key. 

287 :return: a PublicKey object 

288 

289 First let's construct a DER encoded key: 

290 

291 >>> import base64 

292 >>> b64der = 'MAwCBQCNGmYtAgMBAAE=' 

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

294 

295 This loads the file: 

296 

297 >>> PublicKey._load_pkcs1_der(der) 

298 PublicKey(2367317549, 65537) 

299 

300 """ 

301 

302 from pyasn1.codec.der import decoder 

303 from rsa.asn1 import AsnPubKey 

304 

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

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

307 

308 def _save_pkcs1_der(self) -> bytes: 

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

310 

311 :returns: the DER-encoded public key. 

312 :rtype: bytes 

313 """ 

314 

315 from pyasn1.codec.der import encoder 

316 from rsa.asn1 import AsnPubKey 

317 

318 # Create the ASN object 

319 asn_key = AsnPubKey() 

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

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

322 

323 return encoder.encode(asn_key) 

324 

325 @classmethod 

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

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

328 

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

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

331 

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

333 key. 

334 :return: a PublicKey object 

335 """ 

336 

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

338 return cls._load_pkcs1_der(der) 

339 

340 def _save_pkcs1_pem(self) -> bytes: 

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

342 

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

344 :rtype: bytes 

345 """ 

346 

347 der = self._save_pkcs1_der() 

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

349 

350 @classmethod 

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

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

353 

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

355 rather than BEGIN RSA PUBLIC KEY. 

356 

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

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

359 

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

361 key, from OpenSSL. 

362 :type keyfile: bytes 

363 :return: a PublicKey object 

364 """ 

365 

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

367 return cls.load_pkcs1_openssl_der(der) 

368 

369 @classmethod 

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

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

372 

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

374 key, from OpenSSL. 

375 :return: a PublicKey object 

376 """ 

377 

378 from rsa.asn1 import OpenSSLPubKey 

379 from pyasn1.codec.der import decoder 

380 from pyasn1.type import univ 

381 

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

383 

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

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

386 

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

388 

389 

390class PrivateKey(AbstractKey): 

391 """Represents a private RSA key. 

392 

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

394 'd', 'p', 'q' and other values. For example ,in the case of multiprime RSA, 

395 it additionally contains the lists 'rs', 'ds', and 'ts' which contain the 

396 factors, exponents, and coefficients for the other primes. 

397 

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

399 faster, though. 

400 

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

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

403 

404 exp1, exp2 and coef will be calculated: 

405 

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

407 >>> pk.exp1 

408 55063 

409 >>> pk.exp2 

410 10095 

411 >>> pk.coef 

412 50797 

413 

414 """ 

415 

416 __slots__ = ("d", "p", "q", "exp1", "exp2", "coef", "rs", "ds", "ts") 

417 

418 def __init__( 

419 self, 

420 n: int, 

421 e: int, 

422 d: int, 

423 p: int, 

424 q: int, 

425 rs: typing.Optional[typing.List[int]] = None, 

426 ) -> None: 

427 rs = [] if rs is None else rs 

428 

429 AbstractKey.__init__(self, n, e) 

430 self.d = d 

431 self.p = p 

432 self.q = q 

433 

434 # Calculate exponents and coefficient. 

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

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

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

438 

439 # Calculate other primes' exponents and coefficients. 

440 self.rs = rs 

441 self.ds = [int(d % (r - 1)) for r in rs] 

442 Rs = list(itertools.accumulate([p, q] + rs, lambda x, y: x*y)) 

443 self.ts = [pow(R, -1, r) for R, r in zip(Rs[1:], rs)] 

444 

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

446 return getattr(self, key) 

447 

448 def __repr__(self) -> str: 

449 if self.rs: 

450 return "PrivateKey(%i, %i, %i, %i, %i, %s)" % ( 

451 self.n, 

452 self.e, 

453 self.d, 

454 self.p, 

455 self.q, 

456 self.rs, 

457 ) 

458 else: 

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

460 self.n, 

461 self.e, 

462 self.d, 

463 self.p, 

464 self.q, 

465 ) 

466 

467 def __getstate__(self) -> typing.Tuple: 

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

469 if self.rs: 

470 return ( 

471 self.n, 

472 self.e, 

473 self.d, 

474 self.p, 

475 self.q, 

476 self.exp1, 

477 self.exp2, 

478 self.coef, 

479 self.rs, 

480 self.ds, 

481 self.ts, 

482 ) 

483 else: 

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

485 

486 def __setstate__(self, state: typing.Tuple) -> None: 

487 """Sets the key from tuple.""" 

488 if len(state) != 8: 

489 ( 

490 self.n, 

491 self.e, 

492 self.d, 

493 self.p, 

494 self.q, 

495 self.exp1, 

496 self.exp2, 

497 self.coef, 

498 self.rs, 

499 self.ds, 

500 self.ts, 

501 ) = state 

502 else: 

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

504 self.rs = self.ds = self.ts = [] 

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

506 

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

508 if other is None: 

509 return False 

510 

511 if not isinstance(other, PrivateKey): 

512 return False 

513 

514 return all([getattr(self, k) == getattr(other, k) for k in self.__slots__]) 

515 

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

517 return not (self == other) 

518 

519 def __hash__(self) -> int: 

520 if self.rs: 

521 return hash(( 

522 self.n, 

523 self.e, 

524 self.d, 

525 self.p, 

526 self.q, 

527 self.exp1, 

528 self.exp2, 

529 self.coef, 

530 *self.rs, 

531 *self.ds, 

532 *self.ts 

533 )) 

534 else: 

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

536 

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

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

539 

540 :param encrypted: the encrypted message 

541 :type encrypted: int 

542 

543 :returns: the decrypted message 

544 :rtype: int 

545 """ 

546 

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

548 blinded, blindfac_inverse = self.blind(encrypted) 

549 decrypted = rsa.core.decrypt_int_fast( 

550 blinded, 

551 [self.p, self.q] + self.rs, 

552 [self.exp1, self.exp2] + self.ds, 

553 [self.coef] + self.ts, 

554 ) 

555 return self.unblind(decrypted, blindfac_inverse) 

556 

557 @classmethod 

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

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

560 

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

562 key. 

563 :type keyfile: bytes 

564 :return: a PrivateKey object 

565 

566 First let's construct a DER encoded key: 

567 

568 >>> import base64 

569 >>> b64der = 'MC4CAQACBQDeKYlRAgMBAAECBQDHn4npAgMA/icCAwDfxwIDANcXAgInbwIDAMZt' 

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

571 

572 This loads the file: 

573 

574 >>> PrivateKey._load_pkcs1_der(der) 

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

576 

577 """ 

578 

579 from pyasn1.codec.der import decoder 

580 

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

582 

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

584 # 

585 # RSAPrivateKey ::= SEQUENCE { 

586 # version Version, 

587 # modulus INTEGER, -- n 

588 # publicExponent INTEGER, -- e 

589 # privateExponent INTEGER, -- d 

590 # prime1 INTEGER, -- p 

591 # prime2 INTEGER, -- q 

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

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

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

595 # otherPrimeInfos OtherPrimeInfos OPTIONAL 

596 # } 

597 

598 if priv[0] != 0: 

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

600 

601 n, e, d, p, q = map(int, priv[1:6]) 

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

603 rs = map(int, priv[9::3]) 

604 ds = map(int, priv[10::3]) 

605 ts = map(int, priv[11::3]) 

606 

607 key = cls(n, e, d, p, q, list(rs)) 

608 

609 if (key.exp1, key.exp2, key.coef, key.rs, key.ds, key.ts) != (exp1, exp2, coef, rs, ds, ts): 

610 warnings.warn( 

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

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

613 "instead.", 

614 UserWarning, 

615 ) 

616 

617 return key 

618 

619 def _save_pkcs1_der(self) -> bytes: 

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

621 

622 :returns: the DER-encoded private key. 

623 :rtype: bytes 

624 """ 

625 

626 from pyasn1.type import univ, namedtype 

627 from pyasn1.codec.der import encoder 

628 

629 other_fields = [ 

630 ( 

631 namedtype.NamedType("prime%d" % (i + 3), univ.Integer()), 

632 namedtype.NamedType("exponent%d" % (i + 3), univ.Integer()), 

633 namedtype.NamedType("coefficient%d" % (i + 3), univ.Integer()), 

634 ) for i in range(len(self.rs)) 

635 ] 

636 

637 class AsnPrivKey(univ.Sequence): 

638 componentType = namedtype.NamedTypes( 

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

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

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

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

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

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

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

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

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

648 *list(itertools.chain(*other_fields)) 

649 ) 

650 

651 # Create the ASN object 

652 asn_key = AsnPrivKey() 

653 asn_key.setComponentByName("version", 0) 

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

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

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

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

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

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

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

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

662 for i, (r, d, t) in enumerate(zip(self.rs, self.ds, self.ts), start=3): 

663 asn_key.setComponentByName("prime%d" % i, r) 

664 asn_key.setComponentByName("exponent%d" % i, d) 

665 asn_key.setComponentByName("coefficient%d" % i, t) 

666 

667 return encoder.encode(asn_key) 

668 

669 @classmethod 

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

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

672 

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

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

675 

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

677 key. 

678 :type keyfile: bytes 

679 :return: a PrivateKey object 

680 """ 

681 

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

683 return cls._load_pkcs1_der(der) 

684 

685 def _save_pkcs1_pem(self) -> bytes: 

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

687 

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

689 :rtype: bytes 

690 """ 

691 

692 der = self._save_pkcs1_der() 

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

694 

695 

696def find_primes( 

697 nbits: int, 

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

699 accurate: bool = True, 

700 nprimes: int = 2, 

701) -> typing.List[int]: 

702 """Returns a list of different primes with nbits divided evenly among them. 

703 

704 :param nbits: the number of bits for the primes to sum to. 

705 :param getprime_func: the getprime function, defaults to 

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

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

708 :returns: list of primes in descending order. 

709 

710 """ 

711 if nprimes == 2: 

712 return list(find_p_q(nbits // 2, getprime_func, accurate)) 

713 

714 quo, rem = divmod(nbits, nprimes) 

715 factor_lengths = [quo + 1]*rem + [quo] * (nprimes - rem) 

716 

717 while True: 

718 primes = [getprime_func(length) for length in factor_lengths] 

719 if len(set(primes)) == len(primes): 

720 break 

721 

722 return list(reversed(sorted(primes))) 

723 

724 

725def find_p_q( 

726 nbits: int, 

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

728 accurate: bool = True, 

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

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

731 

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

733 will not be equal. 

734 

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

736 :param getprime_func: the getprime function, defaults to 

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

738 

739 *Introduced in Python-RSA 3.1* 

740 

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

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

743 

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

745 >>> from rsa import common 

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

747 256 

748 

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

750 

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

752 >>> from rsa import common 

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

754 True 

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

756 True 

757 

758 """ 

759 

760 total_bits = nbits * 2 

761 

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

763 # factor n. 

764 shift = nbits // 16 

765 pbits = nbits + shift 

766 qbits = nbits - shift 

767 

768 # Choose the two initial primes 

769 p = getprime_func(pbits) 

770 q = getprime_func(qbits) 

771 

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

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

774 

775 - p and q differ 

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

777 """ 

778 

779 if p == q: 

780 return False 

781 

782 if not accurate: 

783 return True 

784 

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

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

787 return total_bits == found_size 

788 

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

790 change_p = False 

791 while not is_acceptable(p, q): 

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

793 if change_p: 

794 p = getprime_func(pbits) 

795 else: 

796 q = getprime_func(qbits) 

797 

798 change_p = not change_p 

799 

800 # We want p > q as described on 

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

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

803 

804 

805def calculate_keys_custom_exponent( 

806 p: int, 

807 q: int, 

808 exponent: int, 

809 rs: typing.Optional[typing.List[int]] = None, 

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

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

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

813 

814 :param p: the first large prime 

815 :param q: the second large prime 

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

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

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

819 :type exponent: int 

820 :param rs: the list of other large primes 

821 

822 """ 

823 

824 phi_n = math.prod([x - 1 for x in [p, q] + ([] if rs is None else rs)]) 

825 

826 try: 

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

828 except rsa.common.NotRelativePrimeError as ex: 

829 raise rsa.common.NotRelativePrimeError( 

830 exponent, 

831 phi_n, 

832 ex.d, 

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

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

835 ) from ex 

836 

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

838 raise ValueError( 

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

840 ) 

841 

842 return exponent, d 

843 

844 

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

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

847 returns them as a tuple (e, d) 

848 

849 :param p: the first large prime 

850 :param q: the second large prime 

851 

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

853 """ 

854 

855 return calculate_keys_custom_exponent(p, q, DEFAULT_EXPONENT) 

856 

857 

858def gen_keys( 

859 nbits: int, 

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

861 accurate: bool = True, 

862 exponent: int = DEFAULT_EXPONENT, 

863 nprimes: int = 2, 

864) -> typing.Tuple: 

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

866 

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

868 

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

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

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

872 with similar signature. 

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

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

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

876 :type exponent: int 

877 :param nprimes: the number of prime factors comprising the modulus. 

878 """ 

879 

880 # Regenerate prime values, until calculate_keys_custom_exponent doesn't raise a 

881 # ValueError. 

882 while True: 

883 primes = find_primes(nbits, getprime_func, accurate, nprimes) 

884 p, q, rs = primes[0], primes[1], primes[2:] 

885 try: 

886 (e, d) = calculate_keys_custom_exponent(p, q, exponent=exponent, rs=rs) 

887 break 

888 except ValueError: 

889 pass 

890 

891 if rs: 

892 return p, q, e, d, rs 

893 else: 

894 return p, q, e, d 

895 

896 

897def newkeys( 

898 nbits: int, 

899 accurate: bool = True, 

900 poolsize: int = 1, 

901 exponent: int = DEFAULT_EXPONENT, 

902 nprimes: int = 2, 

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

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

905 

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

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

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

909 

910 :param nbits: the number of bits required to store the modulus ``n``. 

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

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

913 `n`` may have slightly less bits. 

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

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

916 This requires Python 2.6 or newer. 

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

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

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

920 :type exponent: int 

921 :param nprimes: the number of prime factors comprising the modulus. 

922 

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

924 

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

926 Python 2.6 or newer. 

927 

928 """ 

929 

930 if nbits < 16: 

931 raise ValueError("Key too small") 

932 

933 if poolsize < 1: 

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

935 

936 if nprimes < 2: 

937 raise ValueError("Number of primes (%i) should be >= 2" % nprimes) 

938 

939 # Determine which getprime function to use 

940 if poolsize > 1: 

941 from rsa import parallel 

942 

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

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

945 

946 else: 

947 getprime_func = rsa.prime.getprime 

948 

949 # Generate the key components 

950 result = gen_keys(nbits, getprime_func, accurate=accurate, exponent=exponent, nprimes=nprimes) 

951 if len(result) == 4: 

952 p, q, e, d = result 

953 rs = [] 

954 else: 

955 p, q, e, d, rs = result 

956 

957 # Create the key objects 

958 n = math.prod([p, q] + rs) 

959 

960 return (PublicKey(n, e), PrivateKey(n, e, d, p, q, rs)) 

961 

962 

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

964 

965if __name__ == "__main__": 

966 import doctest 

967 

968 try: 

969 for count in range(100): 

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

971 if failures: 

972 break 

973 

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

975 print("%i times" % count) 

976 except KeyboardInterrupt: 

977 print("Aborted") 

978 else: 

979 print("Doctests done")