def find_key(sigs, q=q): '''takes list of triples (s, r, H(m) as bigint) looks for repeated nonces and recovers nonce and private key ''' #s = k^(-1)(H(m) + xr) mod q #=> k = s^(-1)(H(m) + xr) mod q (1) #r = g^k mod q #s = k^(-1)(H(m) + xr) mod q #r' = g^k' mod q #s' = k'^(-1)(H(m') + xr') mod q #Detecting Repeated Nonce #k == k' ==> r == r #r == r' ==> k probably equals k' # #r = (sk - H(m))/x mod q #r == r'=> (sk - H(m))/x == (s'k - H(m'))/x mod q #=> k(s - s') = H(m) - H(m') mod q #=> K = (H(m) - H(m'))/(s - s') mod q sigs_by_r = {} for s, r, m in sigs: if r not in sigs_by_r: sigs_by_r[r] = (s, m) continue #same r ==> same k? if r in sigs_by_r: sp, mp = sigs_by_r[r] #find nonce k = ((m - mp) * number_theory.mod_inv(s - sp, q)) % q #find private key from nonce x = p43.recover_private_key(None, r, s, k, q, m) return x
def dsa_sign_with_k(H_m, x, k): g, p, q = dsa.g, dsa.p, dsa.q #r = (g^k mod p) mod q r = pow(g, k, p) % q #s = k^(-1)(H(m) + xr) mod q k_inv = number_theory.mod_inv(k, q) s = (k_inv * ((H_m + ((x * r) % q)) % q)) % q return (r, s)
def recover_private_key(m, r, s, k, q, H_m=None): '''recover dsa private key from k and signature''' #s = k^(-1)(H(m) + xr) mod q #==> sk - H(m) = xr (mod q) #==> x = r^(-1)(sk - H(m)) mod q if not H_m: H_m = util.bytes_to_bigint(util.sha1sum(m)) r_inv = number_theory.mod_inv(r, q) x = ((((s * k) % q - H_m) % q) * r_inv) % q return x
def dsa_verify(r, s, m, y, p=p, q=q, g=g, h=util.sha1sum): #check that 0 < r < q and 0 < s < q if 0 >= r or r >= q or 0 >= s or r >= q: return False H_m = util.bytes_to_bigint(h(m)) #w = s^(-1) mod q w = number_theory.mod_inv(s, q) u1 = (H_m * w) % q #u_2 = r*w = r*s^(-1) u2 = (r * w) % q v = ((pow(g, u1, p) * pow(y, u2, p)) % p) % q return v == r
def dsa_sign(m, x, p=p, q=q, g=g, h=util.sha1sum): H_m = util.bytes_to_bigint(h(m)) while True: #generate nonce 1 < k < q k = random.SystemRandom().randrange(1, q - 1) #r = (g^k mod p) mod q r = pow(g, k, p) % q #if r == 0, pick new k and try again if r == 0: continue #s = k^(-1)(H(m) + xr) mod q k_inv = number_theory.mod_inv(k, q) s = (k_inv * ((H_m + ((x * r) % q)) % q)) % q #if s == 0, pick new k and try again if s == 0: continue return (r, s)
def gen_key_pair(bit_length=1024, verbose=False): '''generates an RSA public private key pair and returns d, e, n ''' p = _find_rsa_prime(bit_length / 2) if verbose: print 'p =', p q = _find_rsa_prime(bit_length / 2) if verbose: print 'q =', q n = p * q if verbose: print 'n =', n phi_n = (p - 1) * (q - 1) if verbose: print 'phi(n) =', phi_n #this is not secure (duh!!!) e = 3 d = number_theory.mod_inv(e, phi_n) if verbose: print 'e, d = %d, %d' % (e, d) return d, e, n
if rsa_blob in self._seen: return return rsa.rsa_decrypt(rsa_blob, self._d, self._n) def get_ct(self): pt = "%d something" % int(time.time()) ct = rsa.rsa_encrypt(pt, self._e, self._n) self._seen.add(ct) return ct def get_public_key(self): return self._e, self._n if __name__ == '__main__': oracle = Oracle() ct = oracle.get_ct() #cannot query oracle on ciphertexts it has already seen assert (oracle.query(ct) == None) e, n = oracle.get_public_key() #c' = s^e*c ==> p' = (s^e*c)^d = s*p s = 2 ctp = (pow(s, e, n) * ct) % n ptp = oracle.query(ctp) pt = (ptp * number_theory.mod_inv(s, n)) % n print util.bigint_to_bytes(pt)
#s = k^(-1)(H(m) + xr) mod q k_inv = number_theory.mod_inv(k, q) s = (k_inv * ((H_m + ((x * r) % q)) % q)) % q return (r, s) if __name__ == '__main__': y = 0x84ad4719d044495496a3201c8ff484feb45b962e7302e56a392aee4abab3e4bdebf2955b4736012f21a08084056b19bcd7fee56048e004e44984e2f411788efdc837a0d2e5abb7b555039fd243ac01f0fb2ed1dec568280ce678e931868d23eb095fde9d3779191b8c0299d6e07bbb283e6633451e535c45513b2d33c99ea17 msg = '''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''' r = 548099063082341131477253921760299949438196259240 s = 857042759984254168557880549501802188789837994940 assert (util.sha1sum(msg).encode('hex') == 'd2d0714f014a9784047eaeccf956520045c45265') H_m = util.bytes_to_bigint(util.sha1sum(msg)) r_inv = number_theory.mod_inv(r, dsa.q) for k in range(1, 1 << 16): #x = ((((s*k) % dsa.q + dsa.q - H_m) % dsa.q) * r_inv) % dsa.q x = ((s * k - H_m) * r_inv) % dsa.q if dsa_sign_with_k(H_m, x, k) == (r, s): #if x is actual privake key => y = g^x mod p assert (y == pow(dsa.g, x, dsa.p)) print 'k =', k print 'Private key =', x key_hash = util.sha1sum('%x' % x).encode('hex') assert (key_hash == '0954edd5e0afe5542a4adf012611a91912a3ec16') break