def attack(attack_rsa_obj, publickey, cipher=[]): """Run tests against mersenne composites""" with timeout(attack_rsa_obj.args.timeout): try: p = q = None for i in range(2, int(log2(publickey.n))): i2 = 2**i mersenne = [i2 - 1, i2 + 1] g0, g1 = gcd(mersenne[0], publickey.n), gcd(mersenne[1], publickey.n) if 1 < g0 < publickey.n: p = publickey.n // g0 q = g0 break if 1 < g1 < publickey.n: p = publickey.n // g1 q = g1 break if p is not None and q is not None: priv_key = PrivateKey(int(p), int(q), int(publickey.e), int(publickey.n)) return (priv_key, None) return (None, None) except TimeoutError: return (None, None)
def attack(self, publickey, cipher=[]): """Run fermat attack with a timeout""" try: with timeout(seconds=self.timeout): try: publickey.p, publickey.q = self.fermat(publickey.n) except TimeoutError: return (None, None) except FactorizationError: return (None, None) if publickey.p is not None and publickey.q is not None: try: priv_key = PrivateKey( n=publickey.p, p=int(publickey.p), q=int(publickey.q), e=int(publickey.e), ) return (priv_key, None) except ValueError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Try to uncipher c if m < n/e and small e""" with timeout(self.timeout): try: if publickey.e == 3 or publickey.e == 5: plain = [] if (cipher is None) or (len(cipher) < 1): self.logger.info( "[-] No ciphertexts specified, skiping the cube_root test..." ) return (None, None) for c in cipher: cipher_int = int.from_bytes(c, "big") low = 0 high = cipher_int while low < high: mid = (low + high) >> 1 if pow(mid, publickey.e) < cipher_int: low = mid + 1 else: high = mid plain.append( low.to_bytes((low.bit_length() + 7) // 8, byteorder="big")) return (None, plain) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Same n huge e attack""" if not isinstance(publickey, list): return (None, None) with timeout(self.timeout): try: if len(set([_.n for _ in publickey])) == 1: new_e = 1 for k in publickey: new_e = new_e * k.e new_key = (RSA.construct( (publickey[0].n, new_e)).publickey().exportKey()) tmpfile = tempfile.NamedTemporaryFile() with open(tmpfile.name, "wb") as tmpfd: tmpfd.write(new_key) tmpfd.flush() result = self.attack_rsa_obj.attack_single_key( tmpfile.name) if result: return (self.attack_rsa_obj.priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[]): """Try to factorize using yafu""" with timeout(self.timeout): try: if publickey.n.bit_length() > 1024: self.logger.error( "[!] Warning: Modulus too large for SIQS attack module" ) return (None, None) siqsobj = SiqsAttack(self.attack_rsa_obj, publickey.n) siqsobj.checkyafu() siqsobj.testyafu() if siqsobj.checkyafu() and siqsobj.testyafu(): siqsobj.doattack() if siqsobj.p and siqsobj.q: publickey.q = siqsobj.q publickey.p = siqsobj.p priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Run dixon attack with a timeout""" try: with timeout(seconds=self.timeout): try: if publickey.n <= 10**10: publickey.p, publickey.q = dixon_factor(publickey.n) else: self.logger.info( "[-] Dixon is too slow for pubkeys > 10^10...") return (None, None) except TimeoutError: return (None, None) except FactorizationError: return (None, None) if publickey.p is not None and publickey.q is not None: try: priv_key = PrivateKey( n=publickey.n, p=int(publickey.p), q=int(publickey.q), e=int(publickey.e), ) return (priv_key, None) except ValueError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[]): """Run attack with Euler method""" if not hasattr(publickey, "p"): publickey.p = None if not hasattr(publickey, "q"): publickey.q = None # Euler attack with timeout(self.timeout): try: try: euler_res = self.euler(publickey.n) except: print("Euler: Internal Error") return (None, None) if euler_res and len(euler_res) > 1: publickey.p, publickey.q = euler_res if publickey.q is not None: priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(attack_rsa_obj, publickey, cipher=[]): """Run tests against primorial +-1 composites""" with timeout(attack_rsa_obj.args.timeout): try: limit = 10000 pc = 0 prime = 1 primorial = 1 p = q = None while True: prime = next_prime(prime) primorial *= prime primorial_p1 = [primorial - 1, primorial + 1] g0, g1 = gcd(primorial_p1[0], publickey.n), gcd(primorial_p1[1], publickey.n) if 1 < g0 < publickey.n: p = publickey.n // g0 q = g0 break if 1 < g1 < publickey.n: p = publickey.n // g1 q = g1 break pc += 1 if pc == limit: break if p is not None and q is not None: priv_key = PrivateKey(int(p), int(q), int(publickey.e), int(publickey.n)) return (priv_key, None) return (None, None) except TimeoutError: return (None, None)
def attack(self, publickey, cipher=[]): if not hasattr(publickey, "p"): publickey.p = None if not hasattr(publickey, "q"): publickey.q = None # solve with z3 theorem prover with timeout(self.timeout): try: try: euler_res = self.z3_solve(publickey.n, timeout_amount) except: self.logger.warning("[!] z3: Internal Error.") return (None, None) if euler_res and len(euler_res) > 1: publickey.p, publickey.q = euler_res if publickey.q is not None: priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): if not hasattr(publickey, "p"): publickey.p = None if not hasattr(publickey, "q"): publickey.q = None # solve with z3 theorem prover with timeout(self.timeout): try: try: z3_res = self.z3_solve(publickey.n, self.timeout) except: self.logger.warning("[!] z3: Internal Error.") return (None, None) if z3_res and len(z3_res) > 1: p, q = z3_res publickey.p = p publickey.q = q if publickey.q is not None: priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) else: return (None, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[]): """Run tests against primorial +-1 composites""" with timeout(self.timeout): try: limit = 10000 prime = 1 primorial = 1 p = q = None for x in tqdm(range(0, limit)): prime = next_prime(prime) primorial *= prime primorial_p1 = [primorial - 1, primorial + 1] g0, g1 = gcd(primorial_p1[0], publickey.n), gcd(primorial_p1[1], publickey.n) if 1 < g0 < publickey.n: p = publickey.n // g0 q = g0 break if 1 < g1 < publickey.n: p = publickey.n // g1 q = g1 break if p is not None and q is not None: priv_key = PrivateKey(int(p), int(q), int(publickey.e), int(publickey.n)) return (priv_key, None) return (None, None) except TimeoutError: return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Run tests against mersenne composites""" with timeout(self.timeout): try: p = q = None for i in tqdm(range(2, ilog2(publickey.n)), disable=(not progress)): i2 = 2 ** i mersenne = [i2 - 1, i2 + 1] g0, g1 = gcd(mersenne[0], publickey.n), gcd( mersenne[1], publickey.n ) if 1 < g0 < publickey.n: p = publickey.n // g0 q = g0 break if 1 < g1 < publickey.n: p = publickey.n // g1 q = g1 break if p is not None and q is not None: priv_key = PrivateKey( int(p), int(q), int(publickey.e), int(publickey.n) ) return (priv_key, None) return (None, None) except TimeoutError: return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Same n huge e attack""" if not isinstance(publickey, list): return (None, None) with timeout(self.timeout): try: if len(set([_.n for _ in publickey])) == 1: n = publickey[0].n e_array = [] for k in publickey: e_array.append(k.e) if (cipher is None) or (len(cipher) < 2): self.logger.info( "[-] Lack of ciphertexts, skiping the same_n_huge_e test..." ) return (None, None) # e1*s1 + e2*s2 = 1 _, s1, s2 = gcdext(e_array[0], e_array[1]) # m ≡ c1^s1 * c2*s2 mod n plain = ( powmod(int.from_bytes(cipher[0], "big"), s1, n) * powmod(int.from_bytes(cipher[1], "big"), s2, n)) % n return (None, number.long_to_bytes(plain)) except TimeoutError: return (None, None) return (None, None)
def attack(attack_rsa_obj, publickey, cipher=[]): """Run attack with Pollard Rho""" if not hasattr(publickey, "p"): publickey.p = None if not hasattr(publickey, "q"): publickey.q = None # pollard Rho attack with timeout(attack_rsa_obj.args.timeout): try: try: poll_res = pollard_rho(publickey.n) except RecursionError: print("RecursionError") return (None, None) if poll_res != None: publickey.p = poll_res publickey.q = publickey.n // publickey.p if publickey.q is not None: priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) except TypeError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """ Pisano(mersenne) period factorization algorithm optimal for keys sub 70 bits in less than a minute. The attack is very similar to londahl's """ Fib = Fibonacci(progress=progress) with timeout(self.timeout): try: B1, B2 = ( pow(10, (ilog10(publickey.n) // 2) - 4), 0, ) # Arbitrary selected bounds, biger b2 is more faster but more failed factorizations. try: r = Fib.factorization(publickey.n, B1, B2) except OverflowError: r = None if r is not None: publickey.p, publickey.q = r priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) return (None, None) except TimeoutError: return (None, None) return (None, None)
def attack(attack_rsa_obj, publickey, cipher=[]): """Run attack with Pollard P1 """ if not hasattr(publickey, "p"): publickey.p = None if not hasattr(publickey, "q"): publickey.q = None with timeout(attack_rsa_obj.args.timeout): try: # Pollard P-1 attack try: poll_res = pollard_P_1(publickey.n) except RecursionError: print("RecursionError") return (None, None) if poll_res and len(poll_res) > 1: publickey.p, publickey.q = poll_res if publickey.q is not None: priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n) ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Run attack with Pollard P1""" if not hasattr(publickey, "p"): publickey.p = None if not hasattr(publickey, "q"): publickey.q = None with timeout(self.timeout): try: # Pollard P-1 attack try: poll_res = self.pollard_P_1(publickey.n, progress) except RecursionError: return (None, None) if poll_res and len(poll_res) > 1: publickey.p, publickey.q = poll_res if publickey.q is not None: priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Run attack with Euler method""" if not hasattr(publickey, "p"): publickey.p = None if not hasattr(publickey, "q"): publickey.q = None # Euler attack with timeout(self.timeout): try: try: if ((publickey.n - 1) % 4 == 0): euler_res = self.euler(publickey.n) else: self.logger.error( "[!] Public key modulus must be congruent 1 mod 4 to work with euler method." ) return (None, None) except: return (None, None) if euler_res and len(euler_res) > 1: publickey.p, publickey.q = euler_res if publickey.q is not None: priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[]): """Try an attack where the public key has a common factor with the ciphertext - sourcekris""" if cipher is not None: try: with timeout(self.timeout): return self.comfact(cipher, publickey) except TimeoutError: return (None, None) return (None, None)
def attack(attack_rsa_obj, publickey, cipher=[]): """Try an attack where the public key has a common factor with the ciphertext - sourcekris""" timeout_delay = attack_rsa_obj.args.timeout if cipher is not None: try: with timeout(attack_rsa_obj.args.timeout): return comfact(cipher, publickey) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickeys, cipher=[]): """Hastad attack for low public exponent this has found success for e = 3 """ if not isinstance(publickeys, list): return (None, None) if cipher is None or len(cipher) == 0: return (None, None) with timeout(self.timeout): try: c = [] for _ in cipher: c.append(int.from_bytes(_, byteorder="big")) n = [] e = [] for publickey in publickeys: if publickey.e < 11: n.append(publickey.n) e.append(publickey.e) e = set(e) if len(e) != 1: return (None, None) e = e.pop() if e != 3: return (None, None) result = self.chinese_remainder(n, c) nth = self.find_invpow(result, 3) unciphered = [] unciphered.append( nth.to_bytes((nth.bit_length() + 7) // 8, byteorder="big") ) try: unciphered_ = b"" for i in range(0, len(str(nth)), 3): _ = str(nth)[i : i + 3] unciphered_ += bytes([int(_)]) unciphered.append(unciphered_) except: return (None, None) except TimeoutError: return (None, None) return (None, unciphered)
def attack(self, publickey, cipher=[]): """Factors available online?""" try: wa_enabled = True import wolframalpha app_id = os.environ.get("WA_API_KEY") wa_enabled = app_id != None except Exception: self.logger.warning( "[!] Wolfram Alpha is not enabled, install the lib.") wa_enabled = False if not wa_enabled: self.logger.warning( "[!] Wolfram Alpha is not enabled, check if ENV WA_API_KEY is set." ) self.logger.warning( "[!] follow: https://products.wolframalpha.com/api/documentation/" ) self.logger.warning("[!] export WA_API_KEY=XXXXXX-XXXXXXXXXX") self.wa_client = None return (None, None) else: self.wa_client = wolframalpha.Client(app_id) with timeout(self.timeout): try: factors = self.wa_query_factors(publickey.n) self.logger.info("Factors: %s" % str(factors)) if factors != None and len(factors) > 1: publickey.q = factors[ -1] # Let it be the last prime wich is the bigger one publickey.p = publickey.n // publickey.q priv_key = PrivateKey( p=int(publickey.p), q=int(publickey.q), e=int(publickey.e), n=int(publickey.n), ) return (priv_key, None) else: return (None, None) except Exception as e: self.logger.error( "[*] wolfram alpha could not get a factorization.") self.logger.debug(str(e)) return (None, None) except TimeoutError: return (None, None)
def attack(attack_rsa_obj, publickey, cipher=[]): """Try an attack where q < 100,000, from BKPCTF2016 - sourcekris """ with timeout(attack_rsa_obj.args.timeout): try: for prime in primes(100000): if publickey.n % prime == 0: publickey.q = prime publickey.p = publickey.n // publickey.q priv_key = PrivateKey(int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n)) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(attack_rsa_obj, publickey, cipher=[]): """Wiener's attack """ with timeout(attack_rsa_obj.args.timeout): try: wiener = WienerAttack(publickey.n, publickey.e) if wiener.p is not None and wiener.q is not None: publickey.p = wiener.p publickey.q = wiener.q priv_key = PrivateKey(int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n)) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Try an attack where q < 100,000, from BKPCTF2016 - sourcekris""" with timeout(self.timeout): try: for prime in self.primes(100000): if publickey.n % prime == 0: publickey.q = prime publickey.p = publickey.n // publickey.q priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Wiener's attack""" with timeout(self.timeout): try: wiener = WienerAttack(publickey.n, publickey.e, progress) if wiener.p is not None and wiener.q is not None: publickey.p = wiener.p publickey.q = wiener.q priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Run tests against fermat composites""" with timeout(self.timeout): try: limit = 10000 p = q = None for x in tqdm(range(1, limit), disable=(not progress)): f = gcd(fib(x), publickey.n) if 1 < f < publickey.n: p = publickey.n // f q = f break if p is not None and q is not None: priv_key = PrivateKey(int(p), int(q), int(publickey.e), int(publickey.n)) return (priv_key, None) return (None, None) except TimeoutError: return (None, None)
def attack(attack_rsa_obj, publickey, cipher=[]): """Run tests against fermat composites""" with timeout(attack_rsa_obj.args.timeout): try: limit = 10000 p = q = None for x in tqdm(range(1, limit)): f = gcd(fib(x), publickey.n) if 1 < f < publickey.n: p = publickey.n // f q = f break if p is not None and q is not None: priv_key = PrivateKey(int(p), int(q), int(publickey.e), int(publickey.n)) return (priv_key, None) return (None, None) except TimeoutError: return (None, None)
def attack(self, publickey, cipher=[], progress=True): """Do nothing, used for multi-key attacks that succeeded so we just print the private key without spending any time factoring """ londahl_b = 20000000 with timeout(self.timeout): try: factors = self.close_factor(publickey.n, londahl_b, progress) if factors is not None: p, q = factors priv_key = PrivateKey(int(p), int(q), int(publickey.e), int(publickey.n)) return (priv_key, None) else: return (None, None) except TimeoutError: return (None, None) return (None, None)
def attack(self, publickey, cipher=[], progress=True): """System primes in crypto constants""" with timeout(self.timeout): try: primes = load_system_consts() for prp in tqdm(primes, disable=(not progress)): g = gcd(publickey.n, prp) if publickey.n > g > 1: publickey.q = g publickey.p = publickey.n // publickey.q priv_key = PrivateKey( int(publickey.p), int(publickey.q), int(publickey.e), int(publickey.n), ) return (priv_key, None) except TimeoutError: return (None, None) return (None, None)