def test_gcd_n_phi_n_try_again_q(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0x3f25fbdd02563798a3ee15, 0x3c1e53497fe2626fa6d389, 0x3bf7ae07a1892c3881ee69).write() result = self._run_x509sak( ["genbrokenrsa", "--bitlen", "259", "--gcd-n-phi-n", "-vv"], success_return_codes=[1]) self.assertIn(b"exhausted", result.stderr)
def test_retry_q(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0xd7627ea571293d6bd1dc8d4664bc6ab1).write() result = self._run_x509sak([ "genbrokenrsa", "--bitlen", "256", "-v", "--close-q", "--public-exponent", "3", "-vv" ]) self.assertIn(b"retrying", result.stderr)
def test_create_close_q_rsa_key(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0xd7627ea571293d6bd1dc8d4664bc6ab1).write() self._run_x509sak(["genbrokenrsa", "--bitlen", "256", "--close-q"]) key = RSAPrivateKey.read_pemfile("broken_rsa.key")[0] self.assertEqual(key.n.bit_length(), 256) self.assertEqual(key.p, 0xd7627ea571293d6bd1dc8d4664bc6ab1) self.assertEqual(key.q, key.p + 94) key.check_integrity()
def test_automatic_e(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0xd06bda6bd4031ec96cb8023fd89fc9bb, 0xd578117dc5a445697a7c6e04e09c801f).write() self._run_x509sak(["genbrokenrsa", "--bitlen", "256", "-e", "-1"]) key = RSAPrivateKey.read_pemfile("broken_rsa.key")[0] self.assertEqual(key.n.bit_length(), 256) self.assertEqual(key.p, 0xd06bda6bd4031ec96cb8023fd89fc9bb) self.assertEqual(key.q, 0xd578117dc5a445697a7c6e04e09c801f) self.assertNotEqual(key.e, 0x10001) key.check_integrity()
def __init__(self, cmdname, args): BaseAction.__init__(self, cmdname, args) if (not self._args.force) and os.path.exists(self._args.outfile): raise UnfulfilledPrerequisitesException( "File/directory %s already exists. Remove it first or use --force." % (self._args.outfile)) self._prime_db = PrimeDB(self._args.prime_db, generator_program=self._args.generator) q = self._prime_db.get(args.N_bits) if self._args.verbose >= 1: print("Chosen q = 0x%x" % (q)) bit_diff = args.L_bits - q.bit_length() while True: r = NumberTheory.randint_bits(bit_diff, two_msb_set=True) p = (r * q) + 1 if NumberTheory.is_probable_prime(p): break if self._args.verbose >= 1: print("Chosen p = 0x%x" % (p)) assert (q.bit_length() == args.N_bits) assert (p.bit_length() == args.L_bits) assert ((p - 1) % q == 0) # Non-verifiable method of generating g, see A.2.1 of FIPS 186-4, pg. 41 e = (p - 1) // q while True: h = random.randint(2, p - 2) g = pow(h, e, p) if g == 1: continue break if self._args.verbose >= 1: print("Chosen g = 0x%x" % (g)) dsa_parameters = DSAParameters.create(p=p, q=q, g=g) dsa_parameters.write_pemfile(self._args.outfile)
def test_create_rsa_key(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0xd06bda6bd4031ec96cb8023fd89fc9bb, 0xd578117dc5a445697a7c6e04e09c801f).write() self._run_x509sak(["genbrokenrsa", "--bitlen", "256"]) key = RSAPrivateKey.read_pemfile("broken_rsa.key")[0] self.assertEqual(key.n.bit_length(), 256) self.assertEqual(key.p, 0xd06bda6bd4031ec96cb8023fd89fc9bb) self.assertEqual(key.q, 0xd578117dc5a445697a7c6e04e09c801f) self.assertEqual(key.e, 0x10001) self.assertEqual( key.d, 0x5a360028c4c14b78b770d19ce099e80b0a9b25ab6ae35098ce9e7cc27d08ca19 ) key.check_integrity()
def test_carmichael_totient(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0xd06bda6bd4031ec96cb8023fd89fc9bb, 0xd578117dc5a445697a7c6e04e09c801f).write() self._run_x509sak( ["genbrokenrsa", "--bitlen", "256", "--carmichael-totient"]) key = RSAPrivateKey.read_pemfile("broken_rsa.key")[0] self.assertEqual(key.n.bit_length(), 256) self.assertEqual(key.p, 0xd06bda6bd4031ec96cb8023fd89fc9bb) self.assertEqual(key.q, 0xd578117dc5a445697a7c6e04e09c801f) self.assertEqual(key.e, 0x10001) self.assertEqual( key.d, 0x3504164f03e88396ab0cbc8200b8d91a19a60e66e09d11d9e69f27802917833 ) key.check_integrity()
def test_gcd_n_phi_n(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0x1fd22b50d1e28365855635, 0x3af25062dcf148b85084f5).write() output = self._run_x509sak( ["genbrokenrsa", "--bitlen", "257", "--gcd-n-phi-n", "-v"]).stdout key = RSAPrivateKey.read_pemfile("broken_rsa.key")[0] self.assertEqual(key.n.bit_length(), 257) self.assertEqual(key.p, 0x1fd22b50d1e28365855635) self.assertEqual(key.q, 0xea778f672d05715314fd556a2667dca7743e33da973) self.assertEqual((key.q - 1) % (2 * key.p), 0) self.assertNotEqual(NumberTheory.gcd(key.n, key.phi_n), 1) self.assertEqual(key.e, 0x10001) self.assertIn(b"gcd(n, phi(n)) = p", output) key.check_integrity()
def test_retry_e(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0xd7627ea571293d6bd1dc8d4664bc6ab1).write() # Roughly with p = 0.75 there needs to be at least a retry. The # probability that it fails 10 times in a row without there being a # bug therefore is roughly one in a million. for i in range(10): result = self._run_x509sak([ "genbrokenrsa", "--bitlen", "256", "-f", "-v", "--close-q", "--public-exponent", "3", "-e", "-1", "-vv" ]) if b"retrying" in result.stderr: break else: self.fail( "In 10 tries, never was a retry with a different e value chosen. Highly improbable." )
def test_verbosity(self): with tempfile.TemporaryDirectory() as tempdir, WorkDir(tempdir): PrimeDB().add(0xd7627ea571293d6bd1dc8d4664bc6ab1).write() output = self._run_x509sak( ["genbrokenrsa", "--bitlen", "256", "-v", "--close-q"]).stdout self.assertIn(b"p = 0xd7627ea571293d6bd1dc8d4664bc6ab1", output)
def __init__(self, cmdname, args): BaseAction.__init__(self, cmdname, args) if (not self._args.force) and os.path.exists(self._args.outfile): raise UnfulfilledPrerequisitesException( "File/directory %s already exists. Remove it first or use --force." % (self._args.outfile)) if not self._args.gcd_n_phi_n: self._primetype = "2msb" self._p_bitlen = self._args.bitlen // 2 self._q_bitlen = self._args.bitlen - self._p_bitlen else: self._primetype = "3msb" self._p_bitlen = self._args.bitlen // 3 self._q_bitlen = self._args.bitlen - (2 * self._p_bitlen) - 1 if (self._args.close_q) and (self._p_bitlen != self._q_bitlen): raise UnfulfilledPrerequisitesException( "Generating a close-q keypair with a %d modulus does't work, because p would have to be %d bit and q %d bit. Choose an even modulus bitlength." % (self._args.bitlen, self._p_bitlen, self._q_bitlen)) if self._args.q_stepping < 1: raise InvalidInputException( "q-stepping value must be greater or equal to 1, was %d." % (self._args.q_stepping)) self._log.debug("Selecting %s primes with p = %d bit and q = %d bit.", self._primetype, self._p_bitlen, self._q_bitlen) self._prime_db = PrimeDB(self._args.prime_db, generator_program=self._args.generator) p = None q = None while True: if p is None: p = self._prime_db.get(bitlen=self._p_bitlen, primetype=self._primetype) q_generator = self._select_q(p) if q is None: q = next(q_generator) if self._args.gcd_n_phi_n: # q = (2 * r * p) + 1 r = q q = 2 * r * p + 1 if not NumberTheory.is_probable_prime(q): q = None continue # Always make p the smaller factor if p > q: (p, q) = (q, p) n = p * q if self._args.public_exponent == -1: e = random.randint(2, n - 1) else: e = self._args.public_exponent if self._args.carmichael_totient: totient = NumberTheory.lcm(p - 1, q - 1) else: totient = (p - 1) * (q - 1) gcd = NumberTheory.gcd(totient, e) if self._args.accept_unusable_key or (gcd == 1): break else: # Pair (phi(n), e) wasn't acceptable. self._log.debug("gcd(totient, e) was %d, retrying.", gcd) if self._args.public_exponent != -1: # Public exponent e is fixed, need to choose another q. if p.bit_length() == q.bit_length(): # Can re-use q as next p (p, q) = (q, None) q_generator = self._select_q(p) else: # When they differ in length, need to re-choose both values (p, q) = (None, None) rsa_keypair = RSAPrivateKey.create( p=p, q=q, e=e, swap_e_d=self._args.switch_e_d, valid_only=not self._args.accept_unusable_key, carmichael_totient=self._args.carmichael_totient) rsa_keypair.write_pemfile(self._args.outfile) if self._args.verbose >= 1: diff = q - p print("Generated %d bit RSA key:" % (rsa_keypair.n.bit_length())) print("p = 0x%x" % (rsa_keypair.p)) if not self._args.gcd_n_phi_n: print("q = 0x%x" % (rsa_keypair.q)) else: print("q = 2 * r * p + 1 = 0x%x" % (rsa_keypair.q)) print("r = 0x%x" % (r)) print("phi(n) = 0x%x" % (rsa_keypair.phi_n)) print("lambda(n) = 0x%x" % (rsa_keypair.lambda_n)) print("phi(n) / lambda(n) = gcd(p - 1, q - 1) = %d" % (rsa_keypair.phi_n // rsa_keypair.lambda_n)) gcd_n_phin = NumberTheory.gcd(rsa_keypair.n, rsa_keypair.phi_n) if gcd_n_phin == rsa_keypair.p: print("gcd(n, phi(n)) = p") else: print("gcd(n, phi(n)) = 0x%x" % (gcd_n_phin)) if self._args.close_q: print("q - p = %d (%d bit)" % (diff, diff.bit_length())) print("n = 0x%x" % (rsa_keypair.n)) print("d = 0x%x" % (rsa_keypair.d)) print("e = 0x%x" % (rsa_keypair.e))