def srp_connect(addr, name, password): print 'Connecting to %s:%d...' % addr con = socket() con.connect(addr) #C -> S name, A=g^a a, A = gen_key_pair() send_len_payload(con, name) send_bigint(con, A) #S -> C salt, B = kv + g^b salt = recv_len_payload(con) B = recv_bigint(con) #compute u = H(A | B) u = _compute_u(A, B) x = _compute_x(salt, password) #S = (B - kg^x)^(a + ux) = (kv + g^b - kv)^(a + ux) = g^(b(a + ux)) S = pow(B - k * pow(nist_g, x, nist_p), (a + u * x) % nist_p, nist_p) K = sha256sum(bigint_to_bytes(S)) #C -> S send_len_payload(con, hmac_sha256(K, salt)) ok = recv_len_payload(con) if ok != 'ok': print 'SRP failed. Server returned "%s"' % ok return None, None print 'Established shared key: ', K.encode('hex') return con, K
def handle_srp_client(con, addr): #C -> S name, A=g^a name = recv_len_payload(con) if name not in users: send_len_payload(con, 'error: non existant account') con.close() return v, salt = users[name] A = recv_bigint(con) #S -> C salt, B=kv + g^b b = random.SystemRandom().randrange(nist_p) #B = k*v + g^b = kg^H(salt + password) + g^b B = (k * v + pow(nist_g, b, nist_p)) % nist_p send_len_payload(con, salt) send_bigint(con, B) #compute u = H(A | B) u = _compute_u(A, B) #S = (A v^u)^b = (g^a g^(ux))^b = (g^(a + ux))^b = g^(b(a + ux)) S = pow(A * pow(v, u, nist_p), b, nist_p) K = sha256sum(bigint_to_bytes(S)) #C -> S mac(K, salt) tag = recv_len_payload(con) if hmac_sha256(K, salt) != tag: print 'Invalid mac' send_len_payload(con, 'error: invalid mac') con.close() return send_len_payload(con, 'ok') print 'Established shared key: ', K.encode('hex') send_len_payload(con, 'success!!!') con.close()
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)
def send_bigint(con, i): '''sends <length> <bigint>''' return send_len_payload(con, util.bigint_to_bytes(i))
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)
if verbose: print 'e, d = %d, %d' % (e, d) return d, e, n def rsa_encrypt(m, e, n): if isinstance(m, basestring): m = util.bytes_to_bigint(m) return pow(m, e, n) def rsa_decrypt(c, d, n): if isinstance(c, basestring): c = util.bytes_to_bigint(c) return pow(c, d, n) #Don't wan't to wait for params to be generated? ==> use these _sample_params = ( 111362286410211583669725041748624015357015789920103016229885764684530821371586941962831815326506479749001616409906800547275431285766694970292540991623633822700408019631094608796497093656659564366838349269038200838176792713390842709111079260436382859247229353043625367114615775993991276917586476130163934190371L, 3, 167043429615317375504587562622936023035523684880154524344828647026796232057380412944247722989759719623502424614860200820913146928650042455438811487435450759902502377024707831573474592372202008245491689999576946888508161524416942544195053500973486143761844643232694997008489565006093697359038427190720833724177L ) if __name__ == '__main__': d, e, n = gen_key_pair(128, verbose=True) m = 'hello' #message length must be < n c = rsa_encrypt(m, e, n) mp = rsa_decrypt(c, d, n) assert (util.bigint_to_bytes(mp) == m)
def _compute_u(A, B): #compute u = H(A | B) return bytes_to_bigint(sha256sum(bigint_to_bytes(A) + bigint_to_bytes(B)))
#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 padding_oracle(c, d, n, mod_len): '''checks if PKCS #1v1.5 padding is of decryption is correct''' p = util.bigint_to_bytes(rsa.rsa_decrypt(c, d, n)) #pad start with 0s so it has same length as modulus p = '\x00' * (mod_len - len(p)) + p return pkcs1.pkcs1_unpad(p, mod_len) != None
if padding_oracle((pow(s, e, n) * c) % n): found = True break s += 1 r += 1 a, b = _step3([(a, b)], B, n, s)[0] return b if __name__ == '__main__': #don't want to have to wait for key generation each time #256 bit key #d, e, n = (37255313119928308596958693738000904270148055374803475499902820648455212368979L, 3, 55882969679892462895438040607001356405695530651745489982532299779733176320093L) d, e, n = rsa._sample_params m = 'Hello Adrian.' mod_len = pkcs1.num_bytes(n) B = 1 << (8 * mod_len - 16) M = util.bytes_to_bigint(pkcs1.pkcs1_pad(m, mod_len)) c = rsa.rsa_encrypt(M, e, n) p = decrypt(c, e, n, lambda c: fast_oracle(c, d, n, 2 * B, 3 * B)) p = util.bigint_to_bytes(p) #pad start with 0s so it has same length as modulus p = '\x00' * (mod_len - len(p)) + p p = pkcs1.pkcs1_unpad(p, mod_len) print p assert (p == m)
# # ==> 2^(i + 1)*m in [n*lower_{i + 1}, n*(lower_{i + 1} + 1)] # ==> m in [n*lower_{i + 1}/2^(i + 1), n*upper_{i + 1}/2^(i + 1)] # Note: invariant 3 still holds lower <<= 1 else: # 2^(i + 1)*m - 2n*lower in [n, 2n] # ==> 2^(i + 1)*m in [n*(2*lower + 1), n*(2*lower + 2)] # ==> 2^(i + 1)*m in [n*(2*lower + 1), n*2*upper] # upper_{i + 1} = 2*upper # lower_{i + 1} = 2*upper - 1 # Note: invariant 2 still holds # # ==> 2^(i + 1)*m in [n*lower_{i + 1}, n*upper_{i + 1}] # ==> m in [n*lower_{i + 1}/2^(i + 1), n*upper_{i + 1}/2^(i + 1)] # Note: invariant 3 still holds #(lower + 1) * 2 - 1 = 2*lower + 1 lower = (lower << 1) + 1 i = i + 1 # 2^i >= n ==> #The interval [n*lower/2^i, n*upper/2^i] has width <= 1 #integer division by 2^i rounds down ==> use upper bound to find m return ((lower + 1)*n) >> i if __name__ == '__main__': pt = base64.b64decode('VGhhdCdzIHdoeSBJIGZvdW5kIHlvdSBkb24ndCBwbGF5IGFyb3VuZCB3aXRoIHRoZSBGdW5reSBDb2xkIE1lZGluYQ==') d, e, n = rsa._sample_params ct = rsa.rsa_encrypt(pt, e, n) print util.bigint_to_bytes(decrypt(ct, e, n, lambda ct: oracle(ct, d, n)))
import number_theory import rsa import util #see: https://people.freebsd.org/~lstewart/references/apple_tr_kt32_cuberoot.pdf #for computing cube roots if __name__ == '__main__': #get 3 RSA keys all with e = 3 _, e1, n1 = rsa.gen_key_pair(64) _, e2, n2 = rsa.gen_key_pair(64) _, e3, n3 = rsa.gen_key_pair(64) assert ({e1, e2, e3} == {3}) #if same message is encrypted with all keys m = "hello" c1 = rsa.rsa_encrypt(m, 3, n1) c2 = rsa.rsa_encrypt(m, 3, n2) c3 = rsa.rsa_encrypt(m, 3, n3) #then #c_i = m^3 (mod n_i) #So by CTR we can find m^3 (mod n_1*n_2*n_3) m_cubed = number_theory.crt([c1, c2, c3], [n1, n2, n3]) #m < n_i ==> m^3 < n_1*n_2*n_3 #==> we can find m by taking a normal cube root mp = util.bigint_to_bytes(number_theory.ith_root(m_cubed, 3)) assert (m == mp) print 'Recovered message:', mp