def euler(self, n): if n & 1 == 0: return (n >> 1, 2) if n > 2 else (2, 1) end = isqrt(n) a = 0 solutionsFound = [] firstb = -1 while a < end and len(solutionsFound) < 2: bsquare = n - a**2 if bsquare > 0: b = isqrt(bsquare) if (b**2 == bsquare) and (a != firstb) and (b != firstb): firstb = b solutionsFound.append([int(b), a]) a += 1 if len(solutionsFound) < 2: return -1 a = solutionsFound[0][0] b = solutionsFound[0][1] c = solutionsFound[1][0] d = solutionsFound[1][1] k = gcd(a - c, d - b) h = gcd(a + c, d + b) m = gcd(a + c, d - b) l = gcd(a - c, d + b) n = (k**2 + h**2) * (l**2 + m**2) return [int(k**2 + h**2) >> 1, int(l**2 + m**2) >> 1]
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 brent(N): """ Pollard rho with brent optimizations taken from: https://gist.github.com/ssanin82/18582bf4a1849dfb8afd""" if N & 1 == 0: return 2 g = N while g == N: y, c, m = randint(1, N - 1), randint(1, N - 1), randint(1, N - 1) g, r, q = 1, 1, 1 while g == 1: x = y i = 0 while i <= r: y = (powmod(y, 2, N) + c) % N i += 1 k = 0 while k < r and g == 1: ys = y i = 0 while i <= min(m, r - k): y = (powmod(y, 2, N) + c) % N q = q * (abs(x - y)) % N i += 1 g, k = gcd(q, N), k + m if N > g > 1: return g r <<= 1 if g == N: while True: ys = (powmod(ys, 2, N) + c) % N g = gcd(abs(x - ys), N) if N > g > 1: return g
def attack(self, publickey, cipher=[], progress=True): """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), disable=(not progress)): 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 privatekey_check(N, p, q, d, e): ret = False txt = "" nlen = getpubkeysz(N) if is_prime(p) == False: ret = True txt += "p IS NOT PROBABLE PRIME\n" if is_prime(q) == False: txt = "q IS NOT PROBABLE PRIME\n" if gcd(p, e) > 1: ret = True txt = "p and e ARE NOT RELATIVELY PRIME\n" if gcd(q, e) > 1: ret = True txt += "q and e ARE NOT RELATIVELY PRIME\n" if p * q != N: ret = True txt += "n IS NOT p * q\n" if not (abs(p - q) > (2**((nlen >> 1) - 100))): ret = True txt += "|p - q| IS NOT > 2^(nlen/2 - 100)\n" if not (p > 2**((nlen >> 1) - 1)): ret = True txt += "p IS NOT > 2^(nlen/2 - 1)\n" if not (q > 2**((nlen >> 1) - 1)): ret = True txt += "q IS NOT > 2^(nlen/2 - 1)\n" if not (d > 2**(nlen >> 1)): ret = True txt += "d IS NOT > 2^(nlen/2)\n" if not (d < lcm(p - 1, q - 1)): ret = True txt += "d IS NOT < lcm(p-1,q-1)\n" unc = (gcd(e - 1, p - 1) + 1) * (gcd(e - 1, q - 1) + 1) if unc > 9: ret = True txt += "The number of unconcealed messages is %d > min\n" % unc try: inv = invert(e, lcm(p - 1, q - 1)) except: inv = None ret = True txt += "e IS NOT INVERTIBLE mod lcm(p-1,q-1)\n" if d != inv: ret = True txt += "d IS NOT e^(-1) mod lcm(p-1,q-1)" return (ret, txt)
def attack(attack_rsa_obj, publickeys, cipher=[]): """ Common factor attack """ if not isinstance(publickeys, list): return (None, None) # Try to find the gcd between each pair of moduli and resolve the private keys if gcd > 1 priv_keys = [] for x, y in itertools.combinations(publickeys, r=2): if x.n != y.n: g = gcd(x.n, y.n) if g != 1: logger.info("[*] Found common factor in modulus for " + x.filename + " and " + y.filename) # update each attackobj with a private_key x.p = g x.q = x.n // g y.p = g y.q = y.n // g priv_key_1 = PrivateKey(int(x.p), int(x.q), int(x.e), int(x.n)) priv_key_2 = PrivateKey(int(y.p), int(y.q), int(y.e), int(y.n)) priv_keys.append(priv_key_1) priv_keys.append(priv_key_2) priv_keys = list(set(priv_keys)) if len(priv_keys) == 0: priv_keys = None return (priv_keys, None)
def attack(attack_rsa_obj, publickeys, cipher=[]): """ Common factor attack """ if not isinstance(publickeys, list): return (None, None) # Try to find the gcd between each pair of moduli and resolve the private keys if gcd > 1 priv_keys = [] tmp = 1 for x in publickeys: tmp *= x.n for x in publickeys: g = gcd(x.n, tmp) if 1 < g < x.n: logger.info("[*] Found common factor in modulus for " + x.filename) # update each attackobj with a private_key x.p = g x.q = x.n // g priv_key = PrivateKey(int(x.p), int(x.q), int(x.e), int(x.n)) priv_keys.append(priv_key) priv_keys = list(set(priv_keys)) if len(priv_keys) == 0: priv_keys = None return (priv_keys, None)
def pollard_P_1(self, n, progress=True): """Pollard P1 implementation""" z = [] logn = math.log(int(isqrt(n))) prime = primes(997) for j in range(0, len(prime)): primej = prime[j] logp = math.log(primej) for i in range(1, int(logn / logp) + 1): z.append(primej) try: for pp in tqdm(prime, disable=(not progress)): i = 0 x = pp while 1: x = powmod(x, z[i], n) i = i + 1 y = gcd(n, x - 1) if y != 1: p = y q = n // y return p, q if i >= len(z): return 0, None except TypeError: return 0, None
def pre_attack_check(self, publickeys): """Basic pre Attack checks implementation""" if not isinstance(publickeys, list): publickeys = [publickeys] tmp = [] ok = True for publickey in publickeys: if publickey.n & 1 == 0: self.logger.error("[!] Public key: %s modulus should be odd." % publickey.filename) ok = False if gcd(publickey.n, publickey.e) > 1: self.logger.error( "[!] Public key: %s modulus is coprime with exponent." % publickey.filename) ok = False if not (publickey.n > 3): self.logger.error("[!] Public key: %s modulus should be > 3." % publickey.filename) ok = False if is_prime(publickey.n): self.logger.error( "[!] Public key: %s modulus should not be prime." % publickey.filename) ok = False i = isqrt(publickey.n) if publickey.n == (i**2): self.logger.error( "[!] Public key: %s modulus should not be a perfect square." % publickey.filename) publickey.p = i publickey.q = i tmp.append(publickey) ok = False return (tmp, ok)
def common_modulus_attack(self, c1, c2, k1, k2): if k1.n != k2.n: return None if gcd(k1.e, k2.e) != 1: return None deciphered_message = common_modulus(k1.e, k2.e, k1.n, c1, c2) return long_to_bytes(deciphered_message)
def dixon_factor(N, B=7, explain=False): if is_prime(N): return N, 1 start = isqrt(N) if (start ** 2) == N: return start, start base = primes(B) lqbf = pow(base[-1], 2) + 1 QBF = bitarray.bitarray(lqbf) # This is our quasi-bloom-filter basej2N = [] for j in range(0, len(base)): p = powmod(base[j], 2, N) basej2N.append(p) QBF[p] = 1 # We populate our quasi-bloom-filter i = start while i < N: i2N = pow(i, 2, N) if i2N < lqbf and QBF[i2N] == 1: for k in range(0, len(base)): if QBF[basej2N[k]] == 1: # if i2N == basej2N[k]: # this is replaced with a quasi-bloom-filter f = gcd(i - base[k], N) if explain: print("N = %d" % N) print("%d = isqrt(N)" % start) print("%d = pow(%d,2,n)" % (i2N, i)) print("%d = pow(%d,2,n)" % (basej2N[k], base[k])) print("%d - %d = %d" % (i, base[k], f)) print("%d = gcd(%d - % d, N)" % (f, i, base[k])) print( "%d = gcd(%d + % d, N)" % (gcd(i + base[k], N), i, base[k]) ) if 1 < f < N: return f, N // f i += 1 return None, None
def comfact(cipher, publickey): for c in cipher: commonfactor = gcd(publickey.n, s2n(c)) if commonfactor > 1: publickey.q = commonfactor 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)
def attack(attack_rsa_obj, publickey, cipher=[]): """Try an attack where the public key has a common factor with the ciphertext - sourcekris """ if cipher: commonfactor = gcd(publickey.n, s2n(cipher)) if commonfactor > 1: publickey.q = commonfactor 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) return (None, None)
def SQUFOF(N): s = int(isqrt(N) + 0.5) L = int(2 * isqrt(2 * s)) if (s ** 2 == N): return s for k in range(0,len(multiplier)): D = multiplier[k] * N Po = Pprev = P = isqrt(D) Qprev = 1 Q = D - pow(Po, 2) B = 3 * L c0 = True i = 2 while c0: b = int((Po + P) // Q) P = b * Q - P q = Q Q = Qprev + b * (Pprev - P) r = int(isqrt(Q) + 0.5) if (not(i & 1) and (pow(r, 2) == Q)): break Qprev = q Pprev = P i += 1 c0 = (i <= B) b = ((Po - P) // r) Pprev = P = b * r + P Qprev = r Q = (D - pow(Pprev, 2)) // Qprev i = 0 c1 = True while(c1): b = int((Po + P) // Q) Pprev = P P = b * Q - P q = Q; Q = Qprev + b * (Pprev - P) Qprev = q i += 1 c1 = (P != Pprev) r = gcd(N, Qprev) if (1 < r < N): return r,N // r return -1
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 pollard_rho(self, n, seed=2, p=2, mode=1): if n & 1 == 0: return 2 if n % 3 == 0: return 3 if n % 5 == 0: return 5 if is_prime(n): return n if mode == 1: f = lambda x: x**p + 1 else: f = lambda x: x**p - 1 x, y, d = seed, seed, 1 while d == 1: x = f(x) % n y = f(f(y)) % n d = gcd((x - y) % n, n) return None if d == n else d
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)
def attack(self, publickeys, cipher=[]): """Common factor attack""" if not isinstance(publickeys, list): return (None, None) with timeout(self.timeout): try: pubs = [pub.n for pub in publickeys] # Try to find the gcd between each pair of moduli and resolve the private keys if gcd > 1 priv_keys = [] M = ProductTree(pubs) for i in range(0, len(pubs) - 1): pub = pubs[i] x = publickeys[i] R = M // pub g = gcd(pub, R) if pub > g > 1: try: p = g q = pub // g x.p = p x.q = q # update each attackobj with a private_key priv_key_1 = PrivateKey( int(x.p), int(x.q), int(x.e), int(x.n) ) priv_keys.append(priv_key_1) self.logger.info( "[*] Found common factor in modulus for " + x.filename ) except ValueError: continue except TimeoutError: return (None, None) priv_keys = list(set(priv_keys)) if len(priv_keys) == 0: priv_keys = None return (priv_keys, None)
def euler(self, n): if n & 1 == 0: return (n >> 1, 2) if n > 2 else (2, 1) end = isqrt(n) a = 0 solutionsFound = [] firstb = -1 while a < end and len(solutionsFound) < 2: bsquare = n - pow(a, 2) if bsquare > 0: b = isqrt(bsquare) if (pow(b, 2) == bsquare) and (a != firstb) and (b != firstb): firstb = b solutionsFound.append([b, a]) a += 1 if len(solutionsFound) < 2: return None a = solutionsFound[0][0] b = solutionsFound[0][1] c = solutionsFound[1][0] d = solutionsFound[1][1] k = pow(gcd(a - c, d - b), 2) h = pow(gcd(a + c, d + b), 2) m = pow(gcd(a + c, d - b), 2) l = pow(gcd(a - c, d + b), 2) p, q = gcd(k + h, n), gcd(l + m, n) if n > p > 1: return p, n // p if n > q > 1: return q, n // q
def primefac( n, trial_limit=1000, rho_rounds=42000, verbose=False, methods=( _primefac.pollardRho_brent, _primefac.pollard_pm1, _primefac.williams_pp1, _primefac.ecm, _primefac.mpqs, _primefac.fermat, _primefac.factordb, ), timeout=60, ): """Primefac implementation """ from _primefac import isprime, isqrt, primegen from six.moves import xrange, reduce from random import randrange import six timeout = timeout - 1 if n < 2: return if isprime(n): yield n return factors, nroot = [], isqrt(n) # Note that we remove factors of 2 whether the user wants to or not. for p in primegen(): if n % p == 0: while n % p == 0: yield p n //= p nroot = isqrt(n) if isprime(n): yield n return if p > nroot: if n != 1: yield n return if p >= trial_limit: break if isprime(n): yield n return if rho_rounds == "inf": factors = [n] while len(factors) != 0: n = min(factors) factors.remove(n) f = _primefac.pollardRho_brent(n) if isprime(f): yield f else: factors.append(f) n //= f if isprime(n): yield n else: factors.append(n) return factors, difficult = [n], [] while len(factors) != 0: rhocount = 0 n = factors.pop() try: g = n while g == n: x, c, g = randrange(1, n), randrange(1, n), 1 y = x while g == 1: if rhocount >= rho_rounds: raise Exception rhocount += 1 x = (x**2 + c) % n y = (y**2 + c) % n y = (y**2 + c) % n g = gcd(x - y, n) # We now have a nontrivial factor g of n. If we took too long to get here, we're actually at the except statement. if isprime(g): yield g else: factors.append(g) n //= g if isprime(n): yield n else: factors.append(n) except Exception: difficult.append( n ) # Factoring n took too long. We'll have multifactor chug on it. factors = difficult while len(factors) != 0: n = min(factors) factors.remove(n) f = multifactor(n, methods=methods, verbose=verbose, timeout=timeout) if isprime(f): yield f else: factors.append(f) n //= f if isprime(n): yield n else: factors.append(n)
def neg_pow(a, b, n): assert b < 0 assert gcd(a, n) == 1 res = int(gmpy2.invert(a, n)) res = pow(res, b * (-1), n) return res