def hash_password(password, iterations, algorithm="pbkdf2hmac", sub_algorithm="sha512", salt=None, salt_size=16, output_size=32): salt = urandom(salt_size) header = save_data(algorithm, sub_algorithm, iterations, salt_size, output_size, salt) if algorithm == "pbkdf2hmac": return save_data( header, hashlib.pbkdf2_hmac(sub_algorithm, header + password, salt, iterations, output_size)) else: raise ValueError("Unsupported algorithm: '{}'".format(algorithm))
def connect(self, peer_public_key): """ usage: self.connect(peer_public_key) => packet Create a packet for initializing a secure connection with the desired peer. The packet needs no modification, and can be sent as-is via the IO method of choice (i.e. socket.send) The receiving peer should supply the packet to the accept method. """ assert self.stage == "unconnected" packet = save_data( self.key_exchange_protocol.initiate_exchange(peer_public_key)) self.stage = "connecting" return self.send(packet)
def send(self, data): #print "Sender {} incrementing nonce {} -> {} to send:".format(id(self), self.nonce, self.nonce + 1) #if len(data) > 80: # print data[:80] #else: # print data self.nonce += 1 nonce = self.nonce _hash = self.hash_function(str(nonce) + self.state + data) utilities.xor_subroutine(self.state, bytearray(_hash)) return save_data((nonce, _hash, data))
def key_derivation_function(derivation_material, salt=None, output_size=32, algorithm="pbkdf2_hmac", sub_algorithm="sha512", work_factor=100000): salt = salt if salt is not None else urandom(32) header = save_data(algorithm, sub_algorithm, work_factor, len(salt), output_size) return hashlib.pbkdf2_hmac(sub_algorithm, header + derivation_material, salt, work_factor, output_size)
def encrypt(data, public_key, nonce=None, additional_data='', algorithm="sha512", nonce_size=32): """ usage: encrypt(data, public_key, nonce=None, additional_data='', algorithm="sha512", key_size=keyexchange.trapdoor.S_SIZE, nonce_size=32) => cryptogram Encrypts and authenticates data using a randomly generated key and nonce. Authenticates but does not encrypt additional_data algorithm determines which hash algorithm to use with HMAC data/nonce/additional_data should be bytes or bytearray Cryptogram can be decrypted by the holder of the associated private key""" encrypted_key, key = keyexchange.encapsulate_key(public_key) nonce = nonce if nonce is not None else bytearray(random_bytes(nonce_size)) return aead.encrypt(data, serialize_int(key), nonce, save_data(encrypted_key, additional_data), algorithm)
def test_encrypt_decrypt(): key = "\x00" * 16 nonce = "\x00" * 16 data = "A most excellent test message! :)" * 2 additional_data = "Well, integrity is a good thing." cryptogram = bytearray(encrypt(data, key, nonce, additional_data)) header, nonce, additional_data, _data, tag, algorithm = load_data(cryptogram) _cryptogram = save_data(header, nonce, additional_data, '|' + _data[1:], tag, algorithm) plaintext, _additional_data = decrypt(bytes(_cryptogram), key) assert (plaintext, _additional_data) == (None, None), ((plaintext, _additional_data), (data, additional_data)) plaintext, _additional_data = decrypt(bytes(cryptogram), key) assert (plaintext, _additional_data) == (data, additional_data), ((plaintext, _additional_data), (data, additional_data)) print "aead encrypt/decrypt unit test complete"
def encrypt(data, key, nonce=None, additional_data='', algorithm="sha512", nonce_size=32): """ usage: encrypt(data, key, nonce=None, additional_data='', algorithm="sha512") => cryptogram Encrypts and authenticates data using key and nonce. Authenticates but does not encrypt additional_data algorithm determines which hash algorithm to use with HMAC data, key, nonce, and additional_data should be bytes or bytearray. """ data = bytearray(data) key = bytearray(key) nonce = bytearray(nonce if nonce is not None else random_bytes(32)) tag = _hmac_aead_cipher(data, key, nonce, additional_data, algorithm) header = "hmacaead_{}".format(algorithm.lower()) return save_data(header, nonce, additional_data, data, tag)
def accept(self, packet): """ usage: self.accept(packet) => response Initializes a secure connection with the remote peer. Returns a response packet, which the remote peer should supply to the initiator_confirm_connection method. """ assert self.stage == "unconnected" challenge, public_key, ephemeral_public_key = load_data( self.receive(packet)) response = save_data( self.key_exchange_protocol.responder_establish_secret( challenge, public_key, ephemeral_public_key)) self.stage = "accepted:confirming" response = self.send(response) #print("{} confirmed connection".format(id(self))) self.connection_confirmed = True return response
def repackage(cryptogram): header, nonce, additional_data, _data, tag = load_data(cryptogram) return save_data(header, nonce, additional_data, '|' + _data[1:], tag)
def serialize_public_key(public_key): """ usage: serialize_public_key(public_key) => serialized_public_key Returns a saved public key, in the form of bytes. """ return save_data(public_key)