def encrypt(self, plain_text, QB, E=None, P=None, output_type="x only"): if E is not None: self.E = E if P is not None: if isinstance(P, int): y2 = (fast_power(P, 3, self.E.modulus) + (P * self.E.A) + self.E.B) % self.E.modulus y = mod_sqrt(y2, self.E.modulus)[0] self.P = (P, mod_sqrt(y, self.E.modulus)[0]) self.P = P if QB is not None: if isinstance(QB, int): y2 = (fast_power(QB, 3, self.E.modulus) + (QB * self.E.A) + self.E.B) % self.E.modulus y = mod_sqrt(y2, self.E.modulus)[0] QB = (QB, mod_sqrt(y, self.E.modulus)[0]) M = self.E.msg_to_point(plain_text) k = random.randint(1, self.E.modulus) C1 = self.E.multiply(k, P) C2 = self.E.add(M, E.multiply(k, QB)) if output_type == self.style[0]: return (C1, C2) elif output_type == self.style[1]: return (C1[0], C2[0]) else: print("Invalid type") return None
def public_keygen(self, E=None, P=None, private_key=None, output_type="x only"): if E is not None: self.E = E if P is not None: if isinstance(P, int): y2 = (fast_power(P, 3, self.E.modulus) + (P * self.E.A) + self.E.B) % self.E.modulus y = mod_sqrt(y2, self.E.modulus)[0] self.P = (P, mod_sqrt(y, self.E.modulus)[0]) self.P = P if private_key is not None: self.private_key = private_key if None in [self.E, self.P, self.private_key]: return None self.QA = self.E.multiply(self.P, self.private_key) if output_type == self.style[0]: return self.QA elif output_type == self.style[1]: return self.QA[0] else: print("invalid type") return None
def decrypt(self, g=None, modulus=None, private_key=None, cipher_text_1=None, cipher_text_2=None): if private_key is not None: self.set_private_key(private_key) if g is not None: self.set_g(g) if modulus is not None: self.set_modulus(modulus) if cipher_text_1 is not None: self.set_cipher_text_1(cipher_text_1) if cipher_text_2 is not None: self.set_cipher_text_2(cipher_text_2) if None not in [ self.private_key, self.g, self.modulus, self.cipher_text_1, self.cipher_text_2 ]: x = mod_inv( fast_power(self.cipher_text_1, self.private_key, self.modulus), self.modulus) self.message = (x * self.cipher_text_2) % self.modulus return self.message else: return None
def test_fast_power_1(self): print("\n\nRunning test for src module: fast_power") x = 3 e = 218 m = 1000 result = 489 self.assertEqual(fast_power(x, e, m), result)
def bsgs( g, h, p, smoothness=10000 ): # Solving x given g,h,p for the equation g^x (mod p) = h, so logg(h) (mod p) = x N = order(g, p, smoothness) n = int(sqrt(N)) + 1 e = 1 u = mod_inv(fast_power(g, n, p), p) uk = u gi = g hui = (h * uk) % p list_one = {gi: 1} list_two = {hui: 1} # Create the two list for i in range(2, n + 1): gi = (gi * g) % p uk = (uk * u) % p hui = (h * uk) % p list_one.update({gi: i}) list_two.update({hui: i}) # Now Check for a collision between the list for huk in list_two.keys(): for gk in list_one.keys(): if huk == gk: x = (list_one.get(gk) + (list_two.get(huk) * n)) % N xs = [] for i in range(0, int(((p - 1) / N) + 1)): xs.append(x + N * i) return xs
def primality_test(n, certainty=50000 ): #returns true if n is prime, if composite returns false if not isinstance(n, int): raise ValueError("n cannot be anything but an int you gave: " + str(type(n))) elif n < 1: raise ValueError("n cannot be less than 0") elif n == 1: return True elif n % 2 == 0: return False else: for i in range(0, certainty): a = random.randint(2, n - 1) if eea(a, n).get("gcd") != 1: return False k = 1 q = (n - 1) / 2 while q % 2 == 0: k = k + 1 q = q / 2 a = fast_power(a, q, n) if a == 1: continue while k > 1: if a == -1: break a = (a * a) % n k = k - 1 if a == -1: continue return True
def order(g, p, smooth=10000): # Naive order method if p < 1000: for i in range(1, p): if fast_power(g, i, p) == 1: ord = i return ord h = p - 1 divisors = naive_factor(h).get("divisors") # Prime factors and divisors retrieved for ord in sorted( divisors ): # This should iterate smallest to largest, that way we get teh smallest divisor of e result = fast_power(g, ord, p) if result == 1: # divisor is the order of g return ord
def decrypt(self, c1, c2, QA=None): if QA is not None: self.QA = QA if isinstance(c1, int): y2 = (fast_power(c1, 3, self.E.modulus) + (c1 * self.E.A) + self.E.B) % self.E.modulus y = mod_sqrt(y2, self.E.modulus)[0] c1 = (c1, y) if isinstance(c2, int): y2 = (fast_power(c2, 3, self.E.modulus) + (c2 * self.E.A) + self.E.B) % self.E.modulus y = mod_sqrt(y2, self.E.modulus)[0] c2 = (c2, y) param2 = self.E.multiply(self.private_key, c1) param2[1] = -param2[1] return self.E.point_to_msg(self.E.add(c2, param2))
def test_bsgs_1(self): # Book Example print("\n\nRunning test for cryptanalysis module: bsgs") g = 9704 exp_x = 1159 p = 17389 h = fast_power(g, exp_x, p) xs = bsgs(g, h, p) self.assertIn(exp_x, xs)
def gen_symmetric_key(self, B=None, private_key=None, p=None): if B is not None: self.set_public_key(B) if private_key is not None: self.set_private_key(private_key) if p is not None: self.set_modulus(p) if None not in (self.B, self.private_key, self.p): self.symmetric_key = fast_power(self.B, self.private_key, self.p) return self.symmetric_key else: return None
def gen_my_public_key(self, g=None, private_key=None, p=None): if g is not None: self.set_generator(g) if private_key is not None: self.set_private_key(private_key) if p is not None: self.set_modulus(p) if None not in (self.g, self.private_key, self.p): self.A = fast_power(self.g, self.private_key, self.p) return self.A else: return None
def __init__(self, E, P): self.E = E self.style = ["whole point", "x only"] if isinstance(P, int): y2 = (fast_power(P, 3, self.E.modulus) + (P * self.E.A) + self.E.B) % self.E.modulus y = mod_sqrt(y2, self.E.modulus)[0] self.P = (P, mod_sqrt(y, self.E.modulus)[0]) self.P = P
def encrypt(self, m, N = None, e = None): if N is not None: self.N = N if e is not None: self.e = e self.m = m if None in [self.N, self.e, self.m]: raise ValueError("m, e, or N is None") self.c = fast_power(self.m, self.e, self.N) return self.c
def pollard(N): a = 2 p = None for j in range(2, 1000): a = fast_power(a, j, N) d = eea(a-1, N).get("gcd") if d > 1 and d < N: p = d break return p
def legendre_symbol(a, modulus): ap = fast_power(a, (modulus-1)/2, modulus) l_symb = None if a==0: l_symb = 0 elif ap == 1: # a is a quadratic residue mod modulus l_symb = 1 elif ap == ((-1) % modulus):# a is a non-quadratic residue mod modulus l_symb = -1 return l_symb
def encrypt(self, message=None, g=None, public_key=None, modulus=None, k=None): if g is not None: self.set_g(g) if public_key is not None: self.set_public_key(public_key) if modulus is not None: self.set_modulus(modulus) #Validate k if k is None: if self.modulus is not None: self.k = random.randint(2, self.modulus - 2) #print("k: "+str(self.k)) else: return None elif k <= 1 or k >= self.modulus - 1: print("Invalid k value") return None else: self.k = k if isinstance(message, int): #Validate message if message <= 2 or message >= self.modulus - 1: print("Invalid message size, must be in range 2-p-2") return None else: if None not in [self.g, self.public_key]: self.message = message self.cipher_text_1 = fast_power(self.g, self.k, self.modulus) self.cipher_text_2 = (self.message * fast_power( self.public_key, self.k, self.modulus)) % self.modulus return [self.cipher_text_1, self.cipher_text_2] else: print("g or public key is none") return None else: return None
def pohlig_hellman( g, h, p ): #Solving x given g,h,p for the equation g^x (mod p) = h, so logg(h) (mod p) = x n = p - 1 congruences_and_mods = [] prime_factors = naive_factor(n, 10000).get("prime_factors_dict") for factor in prime_factors.keys(): modulo = factor**prime_factors.get(factor) gi = fast_power(g, n / modulo, p) hi = fast_power(h, n / modulo, p) ax = bsgs( gi, hi, p)[0] # retuns a list of solutions, we just want the first one congruences_and_mods.append((ax, modulo)) x = crt(congruences_and_mods) N = order(g, p, 10000) xs = [] for i in range(1, int(((p - 1) / N) + 1)): xs.append(int((x + N * i) % n)) return xs
def gen_public_key(self, private_key=None, g=None, modulus=None): if private_key is not None: self.set_private_key(private_key) if g is not None: self.set_g(g) if modulus is not None: self.set_modulus(modulus) if None in [self.private_key, self.modulus, self.g]: return None else: self.public_key = fast_power(self.g, self.private_key, self.modulus) return self.public_key
def decrypt(self, c, p = None, q = None, e = None): if q is not None and p is not None: self.q = q self.p = p self. N = self.p * self.q if e is not None: self.e = e self.c = c if None in [self.N, self.p, self.q, self.e, self.c]: raise ValueError("c, e, p, q, or N is None") g = eea(self.p - 1, self.q-1).get("gcd") self.d = int(mod_inv(self.e % ((self.p-1)*(self.q-1)/g), (self.p-1)*(self.q-1)/g)) self.m = fast_power(self.c, self.d, self.N) return self.m
def test_bsgs_2(self): primes = small_primes_generator( 1000) # Change this to increase/decrease duration of test del primes[0] # delete 2, all of these are trivial del primes[0] # delete 3 del primes[0] # delte 5 for prime in primes: for j in range(1, 10): g = random.randint(2, prime - 1) for i in range(1, 10): expected_x = random.randint(1, prime - 1) h = fast_power(g, expected_x, prime) xs = bsgs(g, h, prime) #print(" | prime: "+str(prime) + " | g: "+str(g) + " | exp_x: "+str(expected_x)+" | h: "+str(h)+ " | xs: " + str(xs)) self.assertIn(expected_x, xs)
def symmetric_keygen(self, QB, private_key=None, output_type="x only"): if private_key is not None: self.private_key = private_key if QB is not None: self.QB = QB if None in [self.E, self.private_key]: return None if isinstance(self.QB, int): y2 = (fast_power(self.QB, 3, self.E.modulus) + (self.QB * self.E.A) + self.E.B) % self.E.modulus y = mod_sqrt(y2, self.E.modulus)[0] self.QB = (self.QB, y) print("QB:") print(QB) sym_point = self.E.multiply(self.QB, self.private_key) sym_key = sym_point[0] if output_type == self.style[0]: return sym_point elif output_type == self.style[1]: return sym_key else: print("invalid output type") return None
def mod_sqrt(a, modulus): root1 = None root2 = None if legendre_symbol(a, modulus) != 1: root1 = None root2 = None elif modulus % 2 == 0: # Non-prime modulus's are not supported print("Not a prime") root1 = None root2 = None elif modulus % 8 == 1 or modulus % 8 == 5: s = 0 m = None n = modulus - 1 while n % 2 == 0: n = n / 2 s += 1 m = n e = s z = random.randint(1, modulus - 1) while legendre_symbol(z, modulus) != -1: # z is a non-quadratic residue z = random.randint(1, modulus - 1) c = fast_power(z, m, modulus) x = fast_power(a, (m + 1) / 2, modulus) t = fast_power(a, m, modulus) while t != 1: i = 1 for i in range(1, e): if fast_power(t, 2**i, modulus) == 1: break b = fast_power(c, 2**(e - i - 1), modulus) x = (b * x) % modulus t = (t * b * b) % modulus c = (b * b) % modulus e = i root1 = x root2 = modulus - x elif modulus % 8 == 3 or modulus % 8 == 7: x = fast_power(a, (modulus + 1) / 4, modulus) root1 = x root2 = (-x) % modulus return (root1, root2)
def test_fast_power_4(self): x = 11 e = 7234592359-1 m = 7234592359 result = 1 self.assertEqual(fast_power(x, e, m), result)
def test_fast_power_3(self): x = 11 e = 12314 m = 7234592359 result = 1369450571 self.assertEqual(fast_power(x, e, m), result)
def test_fast_power_2(self): x = 5 e = 718 m = 23451 result = 3739 self.assertEqual(fast_power(x, e, m), result)
def calculate_y2(self, x): return (fast_power(x, 3, self.modulus) + (self.A * x) + self.B) % self.modulus