def rsa_dec(self, cipher, pub_key={}, appr="brute"): n = pub_key["n"] e = pub_key["e"] if appr == "brute": p = q = 3 while p < n: if n % p == 0: q = n / p phi = (p - 1) * (q - 1) d = cutils.modinv(e, phi) return self.dec.rsa(cipher, {'d': d, 'p': p, 'q': q}) p += 2 return "" elif appr == "p-1": b = 3 B = 2 while True: b = pow(b, B, n) p = fractions.gcd(b - 1, n) if p > 1 and p < n: q = n / p phi = (p - 1) * (q - 1) d = cutils.modinv(e, phi) return self.dec.rsa(cipher, {'d': d, 'p': p, 'q': q}) if B > math.sqrt(n): return "" #raise Exception("P-1 attack error: bound = {} possible no solution exists for n = {}".format(B, n)) B += 2 return "" else: return None
def verify(self, signedmsg, key, option='e'): ''' Options: e = el_gamal r = rsa d = dsa ''' msg = signedmsg[0].encode('hex') msg = int(msg, 16) # el gamal: if option == 'e': r = int(signedmsg[1], 16) s = int(signedmsg[2], 16) p = key['p'] alpha = key['alpha'] beta = key['beta'] betator = pow(beta, r, p) rtos = pow(r, s, p) v1 = (betator * rtos) % p v2 = pow(alpha, msg, p) return v1 == v2 # rsa elif option == 'r': sig = int(signedmsg[1], 16) e = key['e'] p = key['p'] q = key['q'] n = p * q test = pow(sig, e, n) return msg == test elif option == 'd': r = int(signedmsg[1], 16) s = int(signedmsg[2], 16) p = key['p'] q = key['q'] alpha = key['alpha'] beta = key['beta'] sinv = utils.modinv(s, q) # u1 = s^(-1)*m mod q u1 = pow(sinv * msg, 1, q) # u2 = s^(-1)*r mod q u2 = pow(sinv * r, 1, q) # v = (alpha^u1 * beta^u2 mod p)mod q v = pow(pow(alpha, u1, p) * pow(beta, u2, p), 1, p) % q return v == r else: raise Exception("Unkown verification option:", option, "(e: El Gamal, r: RSA, d: DSA)")
def dsa(self, message, key={}): p = key['p'] q = key['q'] a = key['a'] alpha = key['alpha'] msg = message.encode('hex') msg = int(msg, 16) if msg > q: raise Exception( "WeakKeyError: message is larger than prime (q) potential loss of data" ) if pow(key['alpha'], (p - 1) / 2, p) != 1: raise Exception( "KeyError: private key is not configured correctly") # pick k from 1 to q-1 k = random.randint(1, q - 1) # r = (a^k mod p) mod q r = pow(alpha, k, p) % q # s = k^(-1)(m + a*r) mod q kinv = utils.modinv(k, q) ar = pow(a * r, 1, q) s = pow(kinv * (msg + ar), 1, q) hex_r = hex(int(r))[2:] hex_s = hex(int(s))[2:] if hex_r[-1] == "L": hex_r = hex_r[:-1] if hex_s[-1] == "L": hex_s = hex_s[:-1] return (message, hex_r, hex_s)
def el_gamal(self, message, key={}): p = key['p'] alpha = key['alpha'] a = key['a'] msg = message.encode('hex') msg = int(msg, 16) if msg > p: raise Exception( "WeakKeyError: message is larger than prime (p) potential loss of data" ) # choose k gcd(k,p-1)=1 k = random.randint(3, p - 1) g, _, _ = utils.egcd(k, p - 1) while g != 1: k = random.randint(3, p - 1) g, _, _ = utils.egcd(k, p - 1) # r = alpha**k mod p r = pow(alpha, k, p) # s = k**-1 *(m-a*r) mod p-1 k_inv = utils.modinv(k, p - 1) s = (k_inv * (msg - a * r)) % (p - 1) hex_r = hex(int(r))[2:] hex_s = hex(int(s))[2:] if hex_r[-1] == "L": hex_r = hex_r[:-1] if hex_s[-1] == "L": hex_s = hex_s[:-1] return (message, hex_r, hex_s)
def el_gamal(self, cipher, key={}): p = key['p'] a = key['a'] r = int(cipher[0], 16) t = int(cipher[1], 16) r_pow = pow(r, a, p) r_inv = cutils.modinv(r_pow, p) m = pow(t*r_inv, 1, p) m = hex(int(m))[2:] return m.decode('hex')
def affine_dec(ctext_num, a, b, m): a_inv = modinv(a, m) ptext_num = [(a_inv * (num - b)) % m for num in ctext_num] return ptext_num
# Resources: https://infoscience.epfl.ch/record/164524/files/nscan20.PDF from math import gcd from crypto_utils import modinv x = 0xdeadc0de y = 0x17d7f90a4597fb2bbbb41d1a70f505f0d8c5cb53faaafea259150eb6910fb08fbf1ba40e42de70c596fb0032d132c9c6ce46c650999ad5f14a990d205984260146e2949b819dc8732beceed452701d88b2c8723b410fce739009df89930424c566af5102403981c26c3e75d9c62065a347e815b26984dcd3b5f02fc8a8092051 n = 0x90def3c2c91ae9bf6089ec8857960d567fdbcd7c2c3ea713046977231e65f44e1b91550971d4e5d43b51675fae4ba640add3af02dad4bf68c3ddef3a98907e1e01156de7a4474d9fce2ba8c055f44673c703a72a111a06f8a7b2fe582463938d802e91630e1e1b5483b1774e608eb4368c6bbf4da375319d9a2799bf8a5ae453 e = 0x10001 if __name__ == '__main__': p = gcd(y**e - x, n) q = n // p tot = (p - 1) * (q - 1) d = modinv(e, tot) print(d % 1000000007)
def el_gamal_dec(self, cipher, pub_key={}, appr="shanks"): p = pub_key['p'] alpha = pub_key['alpha'] beta = pub_key['beta'] a = 0 r = cipher[0] t = cipher[1] if appr == "brute": i = 3 while i < p - 1: if beta == pow(alpha, i, p): a = i break i += 1 if i == p - 1: raise Exception("El Gamal brute force attack failed") #print("Private key:",a) return self.dec.el_gamal(cipher=cipher, key={ 'p': p, 'beta': beta, 'alpha': alpha, 'a': a }) elif appr == "shanks": alpha_inv = cutils.modinv(alpha, p) N = int(math.ceil(p**0.5)) if N**2 < p - 1: raise Exception("Shanks attack error: bad choice of N") j_list = [] k_list = [] i = 0 match = set([]) while i <= N: j_list.append(pow(alpha, i, p)) k_list.append(pow(beta * pow(alpha_inv, N * i, p), 1, p)) i += 1 #print(j_list) #print(k_list) match = set(j_list).intersection(k_list) if len(match) == 0: raise Exception( "El Gamal shanks attack failed: match={}".format(match)) match = list(match)[0] j = j_list.index(match) k = k_list.index(match) a = j + N * k #print("Private key:",a) return self.dec.el_gamal(cipher=cipher, key={ 'p': p, 'beta': beta, 'alpha': alpha, 'a': a }) elif appr == "pohlig": factors = cutils.prime_factors(p - 1) #print(factors) alpha_inv = cutils.modinv(alpha, p) x = 0 left = pow(alpha, (p - 1) / 2, p) right = pow(beta, (p - 1) / 2, p) if left == 1: raise Exception( "Pollig-Hellman error: left equal to 1 mod {} therefore solution impossible" .format(p)) if right == 1: x = 0 else: x = 1 i = 2 while (p - 1) % (2**i) == 0: right = pow(pow(alpha_inv, x, p) * beta, 1, p) right = pow(right, (p - 1) / (2**i), p) x = x + 2**(i - 1) * 1 if right == left else x i += 1 a = (x, 2**(i - 1)) limit = math.sqrt(p) #print("a is {} mod {}".format(x, 2**(i-1))) if len(factors) > 1: for prime in factors[1:]: left = pow(alpha, (p - 1) / prime, p) right = pow(beta, (p - 1) / prime, p) #print(right, p, left) x = cutils.dlog(right, p, left, prime) % prime i = 2 while (p - 1) % (prime**i) == 0: right = pow(pow(alpha_inv, x, p) * beta, 1, p) right = pow(right, (p - 1) / (prime**i), p) if right == left: x = (x + prime**(i - 1) * 1) elif right != 0: x = x + prime**(i - 1) * ( cutils.dlog(right, p, left, prime** (i - 1)) % prime**(i - 1)) else: x = x i += 1 #print("a is {} mod {}".format(x, prime**(i-1))) a = (cutils.rem(a[0], a[1], x, prime**(i - 1)), a[1] * prime**(i - 1)) #print("Using a as {} mod {}".format(a[0], a[1])) return self.dec.el_gamal(cipher=cipher, key={ 'p': p, 'beta': beta, 'alpha': alpha, 'a': a[0] }) else: raise Exception("Unknown attack: {}".format(appr))
def generate_keys(algo="el_gamal", prime_length = 31, key = ""): if algo == "el_gamal": p = cutils.find_large_prime(prime_length) alpha = cutils.randroot(p, 2, 100) a = random.randint(3, p-1) # private key beta = pow(alpha, a, p) return {'p': p, 'alpha': alpha, 'beta': beta, 'a': a} elif algo == "rsa": # HMB, this is about to be some Grade A "excellent" code e = 3 while True: p = q = cutils.find_large_prime(prime_length // 2 + 1) while p == q: p = cutils.find_large_prime(prime_length // 2 + 1) phi = (p - 1) * (q - 1) try: d = cutils.modinv(e, phi) except: e += 1 continue return {'d': d, 'e': e, 'p': p, 'q': q} elif algo == "dsa": q = cutils.find_large_prime(prime_length) p = 2*q + 1 while (p - 1) % q != 0 or not cutils.isPrime(p): #print("Testing Prime:", p) p = p + q while not cutils.isPrime(p): p = p + q #print("Found (p, q): {},{}".format(p, q)) g = cutils.randroot(p) alpha = pow(g, (p-1) / q, p) while pow(alpha, q, p) != 1: g = cutils.randroot(p, 2, q-1) alpha = pow(g, (p-1) / q, p) a = random.randint(3, q-1) # private key beta = pow(alpha, a, p) return {'p': p, 'q': q, 'alpha': alpha, 'beta': beta, 'a': a} elif algo == "des": round_keys = [] # Convert key to binary before permutations # Translate message binary_key = bin(int(key.encode('hex'), 16))[2:] while len(binary_key) % 64 != 0: binary_key = "0" + binary_key perm_key = [0] * len(key_perms) for i in range(len(key_perms)): perm_key[i] = binary_key[key_perms[i]] c = perm_key[:28] d = perm_key[28:] for i in range(16): # Circular shift c.append(c.pop(0)) d.append(d.pop(0)) if i not in [0, 1, 8, 15]: # Shift twice c.append(c.pop(0)) d.append(d.pop(0)) pre_perm_key = c + d ## Permutation with discard left_side = "" right_side = "" # Left for i in range(len(left_perm)): left_side += pre_perm_key[left_perm[i]] # Right for i in range(len(right_perm)): right_side += pre_perm_key[right_perm[i]] round_key = left_side + right_side round_keys.append(round_key) return {'k': round_keys} elif algo == 'otp': # Generate key of same length binary_key = "" for _ in range(len(key)): bit = random.getrandbits(1) binary_key += str(bit) return {'key': binary_key} else: return {}