def main(): # Server sends base, prime and k data = requests.get('http://127.0.0.1:5000/').json() prime, base, k = data['prime'], data['base'], data['k'] # Client and server exchange public keys, but the server sends 0 as its public #key. email = b'*****@*****.**'.decode() #Test a few bad public keys which are all 0 mod prime. These allow us to #login without knowing the password for bad_public_key in [0, prime, prime**2, 4 * prime]: server_response = requests.post('http://127.0.0.1:5000/', data={ 'email': email, 'dhA': bad_public_key }).json() #We only need the salt, not the secret key. Convert to bytes to calculate #our bogus hmac salt = bso.int_to_bytes(server_response['salt']) # Hmac is calculated by the client and sent to the server. K = sha256(bso.int_to_bytes(0)).digest() bogus_hmac = bso.bytes_to_hex( hmac(K, salt, lambda val: sha256(val).digest(), 64, 32)) print( requests.post('http://127.0.0.1:5000/', data={ 'HMAC': bogus_hmac }).text)
def verify_hmac(self, recv_hmac): """ Final SRP verification. Computes the hmac which depends depends on the salt and password but also on a Diffie Hellmen shared key. Equates with the hamc submitted by the client Args: recv_hmac (bytes): hmac computed byt he client Returns: string, int: 'OK', 200 if the verification is successful 'Nope', 400 if the verification is unsuccessful """ S = modexp(self.client_public_key * modexp(self.v, self.u, self.prime), self.secret_key, self.prime) hmac_key = sha256(bso.int_to_bytes(S)).digest() salt_bytes = bso.int_to_bytes(self.salt) calc_hmac = hmac(hmac_key, salt_bytes, lambda val: sha256(val).digest(), 64, 32) if recv_hmac == calc_hmac: return 'OK', 200 return 'Nope', 400
def calculate_hmac(self): """Calculates the hmac and returns it. If the password is correct, it it should match the hmac calculated byt the server. returns: bytes: hmac depending on password, salt and server and client keys """ u = sha256( bso.int_to_bytes(self.public_key) + bso.int_to_bytes(self.server_public_key)).hexdigest() u = int(u, 16) #conver salt to bytes for hashing salt_bytes = bso.int_to_bytes(self.salt) password_exp = sha256(salt_bytes + self.user_password).hexdigest() password_exp = int(password_exp, 16) #Calculating the key for hmac S_base = (self.server_public_key - self.k * modexp(self.base, password_exp, self.prime)) % self.prime S_exponent = (self.secret_key + u * password_exp) % self.prime S = modexp(S_base, S_exponent, self.prime) hmac_key = sha256(bso.int_to_bytes(S)).digest() calc_hmac = hmac(hmac_key, salt_bytes, lambda val: sha256(val).digest(), 64, 32) return calc_hmac
def test_hmac(password, salt, u, client_public_key, secret_key, base, real_hmac, prime = NIST_PRIME): """ Takes in all variables used by the server in simple SRP and calculates the hmac. Tests if the calculated hmac matches the true hmac. Args: password (bytes): user password salt (int): salt used in SRP. Should be random u (int): u used in SRP. Should be random client_public_key (int): clients public key secret_key (int): servers secret key base (int): base used in diffie hellman returns: bool: True if simple srp claculation matches hmac given, false otherwise """ salt = bso.int_to_bytes(salt) x = int(sha256(salt + password).hexdigest(), 16) v = modexp(base, x, prime) S = modexp(client_public_key * modexp(v, u, prime), secret_key, prime) hmac_key = sha256(bso.int_to_bytes(S)).digest() calc_hmac = hmac(hmac_key, salt, lambda val:sha256(val).digest(), 64, 32) if real_hmac == calc_hmac: return True return False
def diffiehellman_mitm_sim(prime, base): """This function simulates an exchange between two parties, first using Diffie Hillmann to exchange secret keys and then AES CBC to exchange messages. However, the function uses yield functionality to simulate a man in the middle attack. """ alice = {} #Alice generates their public key an sends to 'bob' alice['dh'] = DiffieHellman(prime, base, secret_key=secrets.randbelow(prime)) alice_pub = alice['dh'].gen_public_key() (prime, base, key_for_bob) = yield (prime, base, alice_pub) #bob recieves 'alice's' public key, generates their own public key and #the shared key. Sends their public key ot 'alice' bob = { 'dh': DiffieHellman(prime, base, secret_key=secrets.randbelow(prime)) } bob_pup = bob['dh'].gen_public_key() bob['dh'].gen_shared_key(key_for_bob) key_for_alice = yield bob_pup ### Alice recieves Bob's public key, generates the shared key and encrypts ### message for bob alice['dh'].gen_shared_key(key_for_alice) alice['sha1'] = SHA1(bso.int_to_bytes(alice['dh'].shared_key)) alice['cipher'] = AES_CBC(alice['sha1'].digest()[:16], secrets.token_bytes(16)) alice_ciphertext = alice['cipher'].encrypt(b'Message to Bob') alice_ciphertext += alice['cipher'].IV ciphertext_for_bob = yield alice_ciphertext #Bob recieves the ciphertext, decrypts it and send a reply. bob['sha1'] = SHA1(bso.int_to_bytes(bob['dh'].shared_key)) bob['cipher'] = AES_CBC(bob['sha1'].digest()[:16], secrets.token_bytes(16)) bob_ciphertext = bob['cipher'].encrypt(b'Message to Alice') bob_ciphertext += bob['cipher'].IV ciphertext_for_alice = yield bob_ciphertext ### Finally alice decrypts bobs reply alice['cipher'].decrypt(ciphertext_for_alice[:-16], ciphertext_for_alice[-16:])
def simulate_communication_with_dh_key(prime, base): """ Simulates a communication between two parties who first exhanges key via diffiehillman and encrypt messages using aes_cbc. Returns two messages, one encrypted by each party """ alice = {} alice['dh'] = DiffieHellman(prime, base, secret_key=secrets.randbelow(prime)) alice_pub = alice['dh'].gen_public_key() #bob recieves alice's public key, generates their own public key and #the shared key. Sends their public key ot alice bob = {'dh':DiffieHellman(prime, base, secret_key=secrets.randbelow(prime))} bob_pub = bob['dh'].gen_public_key() bob['dh'].gen_shared_key(alice_pub) ### Alice recieves Bob's public key, generates the shared key and encrypts ### message for bob alice['dh'].gen_shared_key(bob_pub) alice['message'] = b'Message to Bob' alice['sha1'] = SHA1(bso.int_to_bytes(alice['dh'].shared_key)) alice['cipher'] = AES_CBC(alice['sha1'].digest()[:16], secrets.token_bytes(16)) alice_ciphertext = alice['cipher'].encrypt(alice['message']) alice_ciphertext += alice['cipher'].IV #Bob encrypts his own ciphertext. bob['message'] = b'Message to Alice' bob['sha1'] = SHA1(bso.int_to_bytes(bob['dh'].shared_key)) bob['cipher'] = AES_CBC(bob['sha1'].digest()[:16], secrets.token_bytes(16)) bob_ciphertext = bob['cipher'].encrypt(bob['message']) bob_ciphertext += bob['cipher'].IV ### Check decryption works assert(bso.remove_padding_pkcs7(alice['cipher'].decrypt(bob_ciphertext[:-16], bob_ciphertext[-16:])) == bob['message']) assert(bso.remove_padding_pkcs7(bob['cipher'].decrypt(alice_ciphertext[:-16], alice_ciphertext[-16:])) == alice['message']) ## return ciphertexts for the man in the middle to decrypt return alice_ciphertext, bob_ciphertext
def decrypt(self, ciphertext): ciphertext_hash = sha256(bso.int_to_bytes(ciphertext)).digest() if ciphertext_hash in self.decrypted_ciphertexts_hashes: raise Exception('I have already decrypted this message!') self.decrypted_ciphertexts_hashes.append(ciphertext_hash) return rsa.RSAServer.decrypt(self, ciphertext)
def main(): prime = 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff for base in [1, prime, prime - 1]: messages = simulate_communication_with_dh_key(prime, base) if base == prime: secret_key = 0 else: secret_key = 1 aes_key = SHA1(bso.int_to_bytes(secret_key)).digest()[:16] malcolm = AES_CBC(aes_key, b'0'*16) assert bso.remove_padding_pkcs7(malcolm.decrypt(messages[0][:-16], messages[0][-16:])) == b'Message to Bob' assert bso.remove_padding_pkcs7(malcolm.decrypt(messages[1][:-16], messages[1][-16:])) == b'Message to Alice'
def _password_computation(self, user_password): """Computes a hash of the users password for storing and later computations Args: user_password (bytes): users password Returns: hashed version of the password which is used in SRP """ #Salt needs to be converted to bytes for use in the hash salt_bytes = bso.int_to_bytes(self.salt) #password is padded with salt (a random int) and hased to be used as #an exponent. This same calculation is also done by the client. password_exponent = sha256(salt_bytes + user_password).hexdigest() password_exponent = int(password_exponent, 16) return modexp(self.base, password_exponent, self.prime)
def main(): """Simulate a man in the middle attack on Diffie Hellman key exchange""" prime = 0xffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff base = 2 connection = diffiehellman_mitm_sim(prime, base) # intercept alices public key prime, base, _ = next(connection) # send prime instead of alices public key to bob. Recieve Bobs public key, # which we forget as it is not needs. The shared kill will be 0. connection.send((prime, base, prime)) #Send prime as bob's public key to alice. We have ensured that the shared #hared secret key is 0. Recieve Alice's ciphertext for bob ciphertext_a2b = connection.send(prime) # decrypt malcolm = AES_CBC(SHA1(bso.int_to_bytes(0)).digest()[:16], b'0' * 16) messages = [] messages.append( bso.remove_padding_pkcs7( malcolm.decrypt(ciphertext_a2b[:-16], ciphertext_a2b[-16:]))) #Send the ciphertext to bob. Recieve his response ciphertext_b2a = connection.send(ciphertext_a2b) messages.append( bso.remove_padding_pkcs7( malcolm.decrypt(ciphertext_b2a[:-16], ciphertext_b2a[-16:]))) assert messages[0] == b'Message to Bob' assert messages[1] == b'Message to Alice' return