def bruteforce_repeated_k(args, dataList): p, q, g, y = args for i in range(0, len(dataList)): for j in range(i + 1, len(dataList)): try: msg1, s1, r1, m1 = dataList[i] msg2, s2, r2, m2 = dataList[j] num = int(m1, 16) - int(m2, 16) tmpDivisor = int(s1) - int(s2) div = modinv(tmpDivisor, q) k = (num * div) % q x = ((int(s1) * k - int(sha1(msg1), 16)) * modinv(int(r1), q)) % q assert y == modexp(g, x, p) if sha1(hex(x) [2:-1]) == "ca8f6f7c66fa362d40760d135b763eb8527d3d52": return (k, x) except: pass print "[*] No k was repeated (possibly)" return (0, 0)
def check(self, signature, message): # check is like this: S^e == PAD(H(m)) all = "\x00" + long_to_bytes(signature ** 3) #verify padding, if not return 0 if all[:3] == "\x00\x01\xff": ind = 3 while all[ind] != "\x00": if all[ind] != "\xff": return False ind += 1 """ # correct implementation checks for leftovers at the end ind += 35 if len(all[ind:]) != 0: return False """ else: return False #return whether hashes are the same recovered_hash = all.split("\x00") start = len(recovered_hash[1]) + 2 + 15 recovered_hash = all[start:start+20].encode("hex") return sha1(message) == recovered_hash
def decrypt(self, data): hash = sha1(str(data)) if hash in self.decrypted: return "[*] Error, hash already decrypted" self.decrypted.append(hash) return self.rsa.decrypt(data)
def sign_DSA(p, q, g, x, message): k = random.randint(1, q - 1) r = modexp(g, k, p) % q s = (modinv(k, q) * (int(sha1(message), 16) + x * r)) % q if s == 0 or r == 0: s, r = sign_DSA(p, q, g) return [r, s]
def check_DSA(signature, p, q, g, y, message): r, s = signature assert 0 < r < q assert 0 < s < q w = modinv(s, q) % q u1 = (int(sha1(message), 16) * w) % q u2 = (r * w) % q v = ((modexp(g, u1, p) * modexp(y, u2, p)) % p) % q return v == r
def bruteforce_k(args, max): r, s, hash, q, check = args for k in xrange(max): x = ((s * k - hash) * modinv(r, q)) % q # if the hash wasn't given we could try this: # checking if y == modexp(g, x, p) if sha1(hex(x)[2:-1]) == "0954edd5e0afe5542a4adf012611a91912a3ec16": return (k, x) print "[*] No k found, tried {} possible values".format(k) return (0, 0)
def DSA_from_k(): m = """For those that envy a MC it can be hazardous to your health\nSo be friendly, a matter of life and death, just like a etch-a-sketch\n""" H = int(sha1(m), 16) q = 0xf4f47f05794b256174bba6e9b396a7707e563c5b y = 0x84ad4719d044495496a3201c8ff484feb45b962e7302e56a392aee4abab3e4bdebf2955b4736012f21a08084056b19bcd7fee56048e004e44984e2f411788efdc837a0d2e5abb7b555039fd243ac01f0fb2ed1dec568280ce678e931868d23eb095fde9d3779191b8c0299d6e07bbb283e6633451e535c45513b2d33c99ea17 r = 548099063082341131477253921760299949438196259240 s = 857042759984254168557880549501802188789837994940 check = 0x0954edd5e0afe5542a4adf012611a91912a3ec16 range = 2**16 assert H == 0xd2d0714f014a9784047eaeccf956520045c45265 k, x = bruteforce_k([r, s, H, q, check], range) print "[*] K recovery attack started!" print "[*] k recovered :", k print "[*] private key (x):", x
def BleichenbacherAttack(): e = 3 p, q = getCoprimes(e) oracle = BleichenbacherOracle(p, q, e) n = oracle.n msg = "hi mom" padded = PKCS15(sha1(msg), n, 'SHA-1') #extend the message to be 1024 bits / 256 bytes print "[*] Starting padding of message:" print "[*] Lenght of padded :", len(padded) print "[*] Length of added hex :", len(("\x00" * ((256 - len(padded))))) padded += ("\x00" * ((256 - len(padded)))) print "[*] Final length :", len(padded) number = int(padded.encode("hex"), 16) signature = cubeRoot(number) print "[*] The Bleichenbacher Oracle says the signature is:", oracle.check(signature, msg)