def __init__( self, p=None, q=None, e=None, n=None, d=None, filename=None, password=None ): """Create private key from base components :param p: extracted from n :param q: extracted from n :param e: exponent :param n: n from public key """ self.p = None if p is not None: self.p = p self.q = None if q is not None: self.q = q self.e = None if e is not None: self.e = e self.n = None if n is not None: self.n = n if ( d is None and self.p is not None and self.q is not None and self.e is not None ): t = (p - 1) * (q - 1) self.d = invmod(e, t) elif d is not None: self.d = d self.key = None if p is not None and q is not None: self.key = RSA.construct((self.n, self.e, self.d, self.p, self.q)) elif n is not None and e is not None and d is not None: try: self.key = RSA.construct((self.n, self.e, self.d)) except ValueError: pass elif filename is not None: with open(filename, "rb") as key_data_fd: self.key = serialization.load_pem_private_key( key_data_fd.read(), password=password, backend=default_backend() ) private_numbers = self.key.private_numbers() if p is None: self.p = private_numbers.p if q is None: self.q = private_numbers.q if d is None: self.d = private_numbers.d if self.p and self.q: self.n = self.p * self.q
def close_factor(self, n, b, progress=True): # approximate phi phi_approx = n - 2 * isqrt(n) + 1 # create a look-up table look_up = {} z = 1 for i in tqdm(range(0, b + 1), disable=(not progress)): look_up[z] = i z = (z * 2) % n # check the table mu = invmod(powmod(2, phi_approx, n), n) fac = powmod(2, b, n) for i in tqdm(range(0, b + 1), disable=(not progress)): if mu in look_up: phi = phi_approx + (look_up[mu] - i * b) break mu = (mu * fac) % n else: return None m = n - phi + 1 roots = ((m - isqrt(m**2 - 4 * n)) >> 1, (m + isqrt(m**2 - 4 * n)) >> 1) if roots[0] * roots[1] == n: return roots
def attack(attack_rsa_obj, publickey, cipher=[]): """Factors available online? """ try: url_1 = "http://factordb.com/index.php?query=%i" url_2 = "http://factordb.com/index.php?id=%s" s = requests.Session() r = s.get(url_1 % publickey.n, verify=False) regex = re.compile(r"index\.php\?id\=([0-9]+)", re.IGNORECASE) ids = regex.findall(r.text) # check if only 1 factor is returned if len(ids) == 2: # theres a chance that the only factor returned is prime, and so we can derive the priv key from it regex = re.compile(r"<td>P<\/td>") prime = regex.findall(r.text) if len(prime) == 1: # n is prime, so lets get the key from it d = invmod(publickey.e, publickey.n - 1) # construct key using only n and d priv_key = PrivateKey(e=int(publickey.e), n=int(publickey.n), d=d) return (priv_key, None) elif len(ids) == 3: try: regex = re.compile(r'value="([0-9\^\-]+)"', re.IGNORECASE) p_id = ids[1] r_1 = s.get(url_2 % p_id, verify=False) key_p = regex.findall(r_1.text)[0] publickey.p = int(key_p) if key_p.isdigit() else solveforp( key_p) q_id = ids[2] r_2 = s.get(url_2 % q_id, verify=False) key_q = regex.findall(r_2.text)[0] publickey.q = int(key_q) if key_q.isdigit() else solveforp( key_q) except IndexError: return (None, None) priv_key = PrivateKey( p=int(publickey.p), q=int(publickey.q), e=int(publickey.e), n=int(publickey.n), ) return (priv_key, None) return (None, None) except: return (None, None)
def partial_q(self, e, dp, dq, qi, part_q, progress=True): """Search for partial q. Tunable to search longer. """ N = 100000 for j in tqdm(range(N, 1, -1), disable=(not progress)): q = (e * dq - 1) / j + 1 if str(hex(q)).strip("L").endswith(part_q): break for k in tqdm(range(1, N, 1), disable=(not progress)): p = (e * dp - 1) / k + 1 try: m = invmod(q, p) if m == qi: break except: pass print("p = " + str(p)) print("q = " + str(q))
def close_factor(self, n, b, progress=True): # approximate phi phi_approx = n - 2 * isqrt(n) + 1 # create a look-up table look_up = {} z = 1 for i in tqdm(range(0, b + 1), disable=(not progress)): look_up[z] = i z = (z << 1) % n # check the table mu = invmod(powmod(2, phi_approx, n), n) fac = powmod(2, b, n) for i in tqdm(range(0, b + 1), disable=(not progress)): if mu in look_up: phi = phi_approx + (look_up[mu] - (i * b)) r = trivial_factorization_with_n_phi(n, phi) if r != None: return r mu = (mu * fac) % n else: return None
def print_results(args, publickey, private_key, uncipher): """Print results to output""" logger = logging.getLogger("global_logger") if ((args.private and private_key is not None) or (args.dumpkey) or (args.uncipher and uncipher not in [None, []])): if publickey is not None: logger.info("\nResults for %s:" % publickey) if private_key is not None: if not isinstance(private_key, list): private_keys = [private_key] else: private_keys = private_key if args.private: logger.info("\nPrivate key :") for priv_key in private_keys: if priv_key is not None: if args.output: try: with open(args.output, "a") as output_fd: output_fd.write("%s\n" % str(priv_key)) except: logger.error("Can't write output file : %s" % args.output) if str(priv_key) != "": logger.info(priv_key) else: logger.warning( "Key format seems wrong, check input data to solve this." ) if args.dumpkey: for priv_key in private_keys: if priv_key.n is not None: logger.info("n: " + str(priv_key.n)) if priv_key.e is not None: logger.info("e: " + str(priv_key.e)) if priv_key.d is not None: logger.info("d: " + str(priv_key.d)) if priv_key.p is not None: logger.info("p: " + str(priv_key.p)) if priv_key.q is not None: logger.info("q: " + str(priv_key.q)) if args.ext: dp = priv_key.d % (priv_key.p - 1) dq = priv_key.d % (priv_key.q - 1) pinv = invmod(priv_key.p, priv_key.q) qinv = invmod(priv_key.q, priv_key.p) logger.info("dp: " + str(dp)) logger.info("dq: " + str(dq)) logger.info("pinv: " + str(pinv)) logger.info("qinv: " + str(qinv)) else: if args.private: logger.critical("Sorry, cracking failed.") if args.dumpkey: if args.publickey is not None: for public_key in args.publickey: with open(public_key, "rb") as pubkey_fd: publickey_obj = PublicKey(pubkey_fd.read(), publickey) logger.info("\nPublic key details for %s" % publickey_obj.filename) logger.info("n: " + str(publickey_obj.n)) logger.info("e: " + str(publickey_obj.e)) if args.uncipher: if uncipher is not None: if not isinstance(uncipher, list): uncipher = [uncipher] if len(uncipher) > 0: logger.info("\nUnciphered data :") for uncipher_ in uncipher: if not isinstance(uncipher_, list): uncipher_ = [uncipher_] for c in uncipher_: if args.output: try: with open(args.output, "ab") as output_fd: output_fd.write(c) except: logger.error("Can't write output file : %s" % args.output) logger.info(f"HEX : 0x{c.hex()}") int_big = int.from_bytes(c, "big") int_little = int.from_bytes(c, "little") logger.info(f"INT (big endian) : {int_big}") logger.info(f"INT (little endian) : {int_little}") try: c_utf8 = c.decode("utf-8") logger.info(f"utf-8 : { c_utf8 }") except UnicodeDecodeError: pass try: c_utf16 = c.decode("utf-16") logger.info(f"utf-16 : { c_utf16 }") except UnicodeDecodeError: pass logger.info(f"STR : {repr(c)}") else: logger.critical("Sorry, unciphering failed.")
exit(0) # if dumpkey mode dump the key components then quit if args.key is not None and args.dumpkey: key_data = open(args.key, "rb").read() key = RSA.importKey(key_data) print("n: " + str(key.n)) print("e: " + str(key.e)) if key.has_private(): print("d: " + str(key.d)) print("p: " + str(key.p)) print("q: " + str(key.q)) if args.ext: dp = key.d % (key.p - 1) dq = key.d % (key.q - 1) pinv = invmod(key.p, key.q) qinv = invmod(key.q, key.p) print("dp: " + str(dp)) print("dq: " + str(dq)) print("pinv: " + str(pinv)) print("qinv: " + str(qinv)) exit(0) if args.key is not None and args.isconspicuous: with open(args.key, "rb") as key_fp: key_data = key_fp.read() key = RSA.importKey(key_data) try: pub_key, priv_key = generate_keys_from_p_q_e_n( args.p, args.q, args.e, args.n
def attack(self, publickey, cipher=[]): """Factors available online?""" with timeout(self.timeout): try: url_1 = "http://factordb.com/index.php?query=%i" url_2 = "http://factordb.com/index.php?id=%s" s = requests.Session() r = s.get(url_1 % publickey.n, verify=False) regex = re.compile(r"index\.php\?id\=([0-9]+)", re.IGNORECASE) ids = regex.findall(r.text) # check if only 1 factor is returned if len(ids) == 2: # theres a chance that the only factor returned is prime, and so we can derive the priv key from it regex = re.compile(r"<td>P<\/td>") prime = regex.findall(r.text) if len(prime) == 1: # n is prime, so lets get the key from it d = invmod(publickey.e, publickey.n - 1) # construct key using only n and d priv_key = PrivateKey(e=int(publickey.e), n=int(publickey.n), d=d) return (priv_key, None) elif len(ids) == 3: try: regex = re.compile(r'value="([0-9\^\-]+)"', re.IGNORECASE) p_id = ids[1] r_1 = s.get(url_2 % p_id, verify=False) key_p = regex.findall(r_1.text)[0] publickey.p = (int(key_p) if key_p.isdigit() else self.solveforp(key_p)) q_id = ids[2] r_2 = s.get(url_2 % q_id, verify=False) key_q = regex.findall(r_2.text)[0] publickey.q = (int(key_q) if key_q.isdigit() else self.solveforp(key_q)) if publickey.n != int(publickey.p) * int(publickey.q): return (None, None) except IndexError: return (None, None) try: priv_key = PrivateKey( p=int(publickey.p), q=int(publickey.q), e=int(publickey.e), n=int(publickey.n), ) except ValueError: return (None, None) return (priv_key, None) elif len(ids) > 3: phi = 1 for p in ids[1:]: phi *= int(p) - 1 d = invmod(publickey.e, phi) plains = [] for c in cipher: int_big = int.from_bytes(c, "big") plain1 = pow(int_big, d, publickey.n) plains.append(long_to_bytes(plain1)) return (None, plains) return (None, None) except NotImplementedError: return (None, None) except TimeoutError: return (None, None)
def print_results(args, publickey, private_key, uncipher): """ Print results to output """ logger = logging.getLogger("global_logger") if ((args.private and private_key is not None) or (args.dumpkey) or (args.uncipher and uncipher not in [None, []])): if publickey is not None: logger.info("\nResults for %s:" % publickey) if private_key is not None: if not isinstance(private_key, list): private_keys = [private_key] else: private_keys = private_key if args.private: logger.info("\nPrivate key :") for priv_key in private_keys: if priv_key is not None: if args.output: try: with open(args.output, "a") as output_fd: output_fd.write("%s\n" % str(priv_key)) except: logger.error("Can't write output file : %s" % args.output) logger.info(priv_key) if args.dumpkey: for priv_key in private_keys: if priv_key.n is not None: logger.info("n: " + str(priv_key.n)) if priv_key.e is not None: logger.info("e: " + str(priv_key.e)) if priv_key.d is not None: logger.info("d: " + str(priv_key.d)) if priv_key.p is not None: logger.info("p: " + str(priv_key.p)) if priv_key.q is not None: logger.info("q: " + str(priv_key.q)) if args.ext: dp = priv_key.d % (priv_key.p - 1) dq = priv_key.d % (priv_key.q - 1) pinv = invmod(priv_key.p, priv_key.q) qinv = invmod(priv_key.q, priv_key.p) logger.info("dp: " + str(dp)) logger.info("dq: " + str(dq)) logger.info("pinv: " + str(pinv)) logger.info("qinv: " + str(qinv)) else: if args.private: logger.critical("Sorry, cracking failed.") if args.dumpkey: if args.publickey is not None: for public_key in args.publickey: with open(public_key, "rb") as pubkey_fd: publickey_obj = PublicKey(pubkey_fd.read(), publickey) logger.info("\nPublic key details for %s" % publickey_obj.filename) logger.info("n: " + str(publickey_obj.n)) logger.info("e: " + str(publickey_obj.e)) if args.uncipher: if uncipher is not None: if not isinstance(uncipher, list): uncipher = [uncipher] if len(uncipher) > 0: logger.info("\nUnciphered data :") for uncipher_ in uncipher: if args.output: try: with open(args.output, "ab") as output_fd: output_fd.write(uncipher_) except: logger.error("Can't write output file : %s" % args.output) logger.info(uncipher_) else: logger.critical("Sorry, unciphering failed.")