def pkcs1_pad(msg, bit_length=1024): h = util.sha1sum(msg) bit_length /= 8 bit_length -= len(prefix) bit_length -= len(h) bit_length -= len(pkcs_magic_bytes) #check that there is enought space if bit_length < 0: return None return ''.join([prefix, '\xff' * bit_length, pkcs_magic_bytes, h])
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 check_signature(msg, sig, e, n, bit_length=1024): p = util.bigint_to_bytes(rsa.rsa_encrypt(sig, e, n)) if len(p) > bit_length / 8: return False #pad to bit_length with leading 0 bytes if len(p) < bit_length / 8: p = '\x00' * (bit_length / 8 - len(p)) + p #check that s^e (mod n) starts with #00 01 FF FF ... FF 00 ASN.1 HASH #check for 00 01 FF if not p.startswith(prefix): return False pos = len(prefix) #move past the rest of the FFs while pos < len(p) and p[pos] == '\xff': pos += 1 #check that there is enough space for 00 ASN.1 HASH if pos + len(pkcs_magic_bytes) + 20 > len(p): return False #check for 00 ASN.1 if p[pos:pos + len(pkcs_magic_bytes)] != pkcs_magic_bytes: return False pos += len(pkcs_magic_bytes) #check that hash matches message return p[pos:pos + 20] == util.sha1sum(msg)
#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) 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')
#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 if __name__ == '__main__': sigs = load() x = find_key([(s, r, m) for _, s, r, m in sigs]) if x: print 'Private key =', x h_pk = util.sha1sum( util.bigint_to_bytes(x).encode('hex')).encode('hex') #print 'sha(x) =', h_pk assert (h_pk == 'ca8f6f7c66fa362d40760d135b763eb8527d3d52') else: print 'No repeated nonces found :('
def forge(msg, bit_length=1024): #find x such that x^3 ~= 00 01 FF 00 ASN.1 HASH garbage padding evil = prefix + pkcs_magic_bytes + util.sha1sum(msg) pad = '\x01' * (bit_length / 8 - len(evil)) target = util.bytes_to_bigint(evil + pad) return number_theory.ith_root(target, 3)