def challenge_44(): # Set up `p`, `q` and `g` parameters p = 0x800000000000000089e1855218a0e7dac38136ffafa72eda7859f2171e25e65eac698c1702578b07dc2a1076da241c76c62d374d8389ea5aeffd3226a0530cc565f3bf6b50929139ebeac04f48c3c84afb796d61e5a4f9a8fda812ab59494232c7d2b4deb50aa18ee9e132bfa85ac4374d7f9091abc3d015efc871a584471bb1 q = 0xf4f47f05794b256174bba6e9b396a7707e563c5b g = 0x5958c9d3898b224b12672c0b98e06c60df923cb8bc999d119458fef538b8fa4046c8db53039db620c094c9fa077ef389b5322a559946a71903f990f1f7e0e025e2d7f7cf494aff1a0470f5b64c36b625a097f1651fe775323556fe00b3608c887892878480e99041be601a62166ca6894bdd41a7054ec89f756ba9fc95302291 # Create new DSA instance dsa = DSA(p, q, g) # Read inputs for this challenge from file messages = get_challenge_44_messages() # Iterate over messages for i, msg1 in enumerate(messages): for msg2 in messages[(i+1):]: # Check if the same `k` was used (implies `r` values are equal) if msg1['r'] == msg2['r']: # Use '9th grade math' to recover `k` a = (msg1['m'] - msg2['m']) % q b1 = (msg1['s'] - msg2['s']) % q b2 = set5.modinv(b1, q) k = (a * b2) % q print('Recovered k: {}'.format(k)) # Recover `x` x = dsa.crack_x(k, msg=msg1['msg'], sig=(msg1['r'], msg1['s'])) print('Recovered x: {}'.format(hashlib.sha1(hex(x)[2:].encode()).hexdigest())) # Verify the found private key `x` is the one we are looking for assert_true(hashlib.sha1(hex(x)[2:].encode()).hexdigest() == 'ca8f6f7c66fa362d40760d135b763eb8527d3d52') return
def sign(self, msg, x): k = random.randrange(2, self.q) r = set5.modexp(self.g, k, self.p) % self.q if k == 0: return self.sign(msg, x) s = (set5.modinv(k, self.q) * (self.__get_hash__(msg) + (x*r))) % self.q if s == 0: return self.sign(msg, x) return (r, s), k
def verify(self, msg, sig, y): r, s = sig if not(0 < r and r < self.q): raise ValueError('r not between 0 and q (r={})'.format(r)) if not(0 < s and s < self.q): raise ValueError('s not between 0 and q (s={})'.format(s)) w = set5.modinv(s, self.q) u1 = (self.__get_hash__(msg) * w) % self.q u2 = (r * w) % self.q v = ((set5.modexp(self.g, u1, self.p) * set5.modexp(y, u2, self.p)) % self.p) % self.q return v == r
def verify(mhash, signature, pub_key): r, s = signature[0], signature[1] if r == 0 or s == 0: return False w = modinv(s, q) H = int(mhash, 16) u1 = (H * w) % q u2 = (r * w) % q v = ((pow(g, u1, p) * pow(pub_key, u2, p)) % p) % q return True if v == r else False
def sign(mhash, priv_key): r = 0 s = 0 sha = hashlib.sha1() while r == 0 or s == 0: ephemeral = random.SystemRandom().randint(2, q - 1) r = pow(g, ephemeral, p) % q H = int(mhash, 16) s = (modinv(ephemeral, q) * (H + (priv_key * r))) % q return r, s
def crack_x(self, k, msg, sig): r, s = sig return (((s * k) - self.__get_hash__(msg)) * set5.modinv(r, self.q)) % self.q