Пример #1
0
def hkdf(ikm, l=16, salt=b"0" * 32, info=b""):
    """ HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
    https://tools.ietf.org/html/rfc5869

    ARGS:
        ikm  : input keying material
        l    : length of output keying material in octets
        salt : (optional) salt value (defaults to 32 0s)
        info : (optional) context and application specific information
               (defaults to null string)
    
    Returns:
        okm  : output key material
    """
    hash_len = 32
    extractor = Hmac(b"sha256", salt)
    extractor.update(ikm)
    prk = extractor.digest()

    t = b""
    okm = b""
    for i in range(int(ceil(float(l) / hash_len))):
        expander = Hmac(b"sha256", prk)
        expander.update(t + info + bytes([1 + i]))
        t = expander.digest()
        okm += t

    return okm[:l]
Пример #2
0
def mix_server_one_hop(private_key, message_list):
    """ Implements the decoding for a simple one-hop mix. 

        Each message is decoded in turn:
        - A shared key is derived from the message public key and the mix private_key.
        - the hmac is checked against all encrypted parts of the message
        - the address and message are decrypted, decoded and returned

    """
    G = EcGroup()

    out_queue = []

    # Process all messages
    for msg in message_list:


        ## Check elements and lengths
        if not G.check_point(msg.ec_public_key) or \
               not len(msg.hmac) == 20 or \
               not len(msg.address) == 258 or \
               not len(msg.message) == 1002:
           raise Exception("Malformed input message")

        ## First get a shared key
        shared_element = private_key * msg.ec_public_key
        key_material = sha512(shared_element.export()).digest()
	
        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        ## Check the HMAC
        h = Hmac(b"sha512", hmac_key)        
        h.update(msg.address)
        h.update(msg.message)
        expected_mac = h.digest()

        print "my hmac: " + str(msg.hmac)
        print "ex hmac: " + str(expected_mac[:20])

        if not secure_compare(msg.hmac, expected_mac[:20]):
            raise Exception("HMAC check failure")

        ## Decrypt the address and the message
        iv = b"\x00"*16

        address_plaintext = aes_ctr_enc_dec(address_key, iv, msg.address)
        message_plaintext = aes_ctr_enc_dec(message_key, iv, msg.message)

        # Decode the address and message
        address_len, address_full = unpack("!H256s", address_plaintext)
        message_len, message_full = unpack("!H1000s", message_plaintext)

        output = (address_full[:address_len], message_full[:message_len])
        out_queue += [output]

    return sorted(out_queue)
def mix_server_one_hop(private_key, message_list):
    """ Implements the decoding for a simple one-hop mix. 

        Each message is decoded in turn:
        - A shared key is derived from the message public key and the mix private_key.
        - the hmac is checked against all encrypted parts of the message
        - the address and message are decrypted, decoded and returned

    """
    G = EcGroup()

    out_queue = []

    # Process all messages
    for msg in message_list:

        ## Check elements and lengths
        if not G.check_point(msg.ec_public_key) or \
               not len(msg.hmac) == 20 or \
               not len(msg.address) == 258 or \
               not len(msg.message) == 1002:
            raise Exception("Malformed input message")

        ## First get a shared key
        shared_element = private_key * msg.ec_public_key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        ## Check the HMAC
        h = Hmac(b"sha512", hmac_key)
        h.update(msg.address)
        h.update(msg.message)
        expected_mac = h.digest()[:20]

        if not secure_compare(msg.hmac, expected_mac[:20]):
            raise Exception("HMAC check failure")

        ## Decrypt the address and the message
        iv = b"\x00" * 16
        # Why are we using an all zero IV?!
        # iv = urandom(16)

        address_plaintext = aes_ctr_enc_dec(address_key, iv, msg.address)
        message_plaintext = aes_ctr_enc_dec(message_key, iv, msg.message)

        # Decode the address and message
        address_len, address_full = unpack("!H256s", address_plaintext)
        message_len, message_full = unpack("!H1000s", message_plaintext)

        output = (address_full[:address_len], message_full[:message_len])
        out_queue += [output]

    return sorted(out_queue)
Пример #4
0
def mix_client_one_hop(public_key, address, message):
    """
    Encode a message to travel through a single mix with a set public key. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'OneHopMixMessage' with four parts: a public key, an hmac (20 bytes),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 
    """

    G = EcGroup()
    assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # Use those as the payload for encryption
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()

    ## ADD CODE HERE

    # First get a shared key
    shared_element = private_key * public_key
    key_material = sha512(shared_element.export()).digest()

    # Use different parts of the shared key for different operations
    hmac_key = key_material[:16]
    address_key = key_material[16:32]
    message_key = key_material[32:48]

    ## Encrypt the address and the message
    iv = b"\x00"*16

    address_cipher = aes_ctr_enc_dec(address_key, iv, address_plaintext)
    message_cipher = aes_ctr_enc_dec(message_key, iv, message_plaintext)

    ## Form the HMAC
    h = Hmac(b"sha512", hmac_key)        
    h.update(address_cipher)
    h.update(message_cipher)
    expected_mac = h.digest()[:20]

    
    assert len(address_cipher) == 258
    assert len(message_cipher) == 1002
    assert len(expected_mac) == 20

    return OneHopMixMessage(client_public_key, expected_mac, address_cipher, message_cipher)
def mix_client_one_hop(public_key, address, message):
    """
    Encode a message to travel through a single mix with a set public key. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'OneHopMixMessage' with four parts: a public key, an hmac (20 bytes),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 
    """

    G = EcGroup()
    assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # Use those as the payload for encryption
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    # generate shared element
    shared = public_key.pt_mul(private_key)
    material = sha512(shared.export()).digest()

    # split shared key for different operations
    hmac_key = material[:16]
    address_key = material[16:32]
    message_key = material[32:48]

    # random inistialisation vector
    iv = b"\x00" * 16

    # encoding address and message
    address_cipher = aes_ctr_enc_dec(address_key, iv, address_plaintext)
    message_cipher = aes_ctr_enc_dec(message_key, iv, message_plaintext)

    # generate hmac h
    h = Hmac(b"sha512", hmac_key)
    h.update(address_cipher)
    h.update(message_cipher)
    expected_mac = h.digest()
    expected_mac = expected_mac[:20]

    return OneHopMixMessage(client_public_key, expected_mac, address_cipher,
                            message_cipher)
Пример #6
0
def mix_client_one_hop(public_key, address, message):
    """
    Encode a message to travel through a single mix with a set public key. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'OneHopMixMessage' with four parts: a public key, an hmac (20 bytes),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 
    """

    G = EcGroup()
    assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # Use those as the payload for encryption
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    shared_element = public_key.pt_mul(private_key)
    key_material = sha512(shared_element.export()).digest()

    hmac_key = key_material[:16]
    address_key = key_material[16:32]
    message_key = key_material[32:48]

    ## ADD CODE HERE
    # TODO:
    # - Encode message to be processed by mix_server_one_hop
    # client_public_key is an EC point
    # expected_hmac is the hmac of address_cipher and message_cipher
    # address_cipher and message_cipher are AES-CTR ciphertexts
    # - Make sure mix_server_one_hop decodes message correctly
    iv = b"\x00" * 16

    address_cipher = aes_ctr_enc_dec(address_key, iv, address_plaintext)
    message_cipher = aes_ctr_enc_dec(message_key, iv, message_plaintext)
    h = Hmac(b"sha512", hmac_key)
    h.update(address_cipher)
    h.update(message_cipher)
    expected_mac = h.digest()[:20]

    return OneHopMixMessage(client_public_key, expected_mac, address_cipher,
                            message_cipher)
def mix_client_one_hop(public_key, address, message):
    """
    Encode a message to travel through a single mix with a set public key. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'OneHopMixMessage' with four parts: a public key, an hmac (20 bytes),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 
    """

    G = EcGroup()
    assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # Use those as the payload for encryption
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()
    
    # generate shared element
    shared = public_key.pt_mul(private_key)
    material = sha512(shared.export()).digest()
    
    # split shared key for different operations
    hmac_key = material[:16]
    address_key = material[16:32]
    message_key = material[32:48]
    
    # random inistialisation vector
    iv = b"\x00"*16
    
    # encoding address and message
    address_cipher = aes_ctr_enc_dec(address_key, iv, address_plaintext)
    message_cipher = aes_ctr_enc_dec(message_key, iv, message_plaintext)
    
    # generate hmac h
    h = Hmac(b"sha512",hmac_key)
    h.update(address_cipher)
    h.update(message_cipher)
    expected_mac = h.digest()
    expected_mac = expected_mac[:20]

    return OneHopMixMessage(client_public_key, expected_mac, address_cipher, message_cipher)
Пример #8
0
def mix_client_one_hop(public_key, address, message):
    """
    Encode a message to travel through a single mix with a set public key. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'OneHopMixMessage' with four parts: a public key, an hmac (20 bytes),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 
    """

    G = EcGroup()
    assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # Use those as the payload for encryption
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()

    encryption_key = private_key * public_key
    ek = sha512(encryption_key.export()).digest()
		
    #TODO ADD CODE HERE 	
    
    #get coresponding key parts	
    hmac_key = ek[:16]
    address_key = ek[16:32]
    message_key = ek[32:48]
	 
    #encrypt
    iv = b"\x00"*16
    address_cipher = aes_ctr_enc_dec(address_key, iv, address_plaintext)            
    message_cipher = aes_ctr_enc_dec(message_key, iv, message_plaintext)

    #calculate mac
    h = Hmac(b"sha512", hmac_key)        
    h.update(address_cipher)
    h.update(message_cipher)
    expected_mac = h.digest()
    expected_mac = expected_mac[:20]
      
    return OneHopMixMessage(client_public_key, expected_mac, address_cipher, message_cipher)
Пример #9
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()

    ## ADD CODE HERE
    key_materials = []
    # First go through the list in the regular order
    # in order to extract the key material.
    # It can be done only in this direction because
    # of the blinding factor
    for public_key in public_keys:
        # First get a shared key
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()
        key_materials.insert(0, key_material)
        # Extract a blinding factor for the public_key
        blinding_factor = Bn.from_binary(key_material[48:])
        private_key = blinding_factor * private_key

    address_cipher = address_plaintext
    message_cipher = message_plaintext
    hmacs = []
    # Then we can go in the reverse direction
    # to encapulate the message as many times as necessary
    for j, public_key in enumerate(reversed(public_keys)):
        key_material = key_materials[j]  # this is already in reverse
        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        # Encrypt address & message
        iv = b"\x00" * 16
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)
        # Encrypt hmacs
        new_hmacs = []
        for i, other_mac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00" * 14)
            hmac_ciphertext = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            new_hmacs += [hmac_ciphertext]
        hmacs = new_hmacs
        # Calculate the HMAC
        h = Hmac(b"sha512", hmac_key)

        for other_mac in hmacs:
            h.update(other_mac)
        h.update(address_cipher)
        h.update(message_cipher)
        hmac = h.digest()
        hmacs.insert(0, hmac[:20])

    return NHopMixMessage(client_public_key, hmacs, address_cipher, message_cipher)
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()
    
    # initilise lists for hmacs and blinding_keys
    hmacs = []
    blinding_keys = []
    
    # initilise variables
    address_cipher = address_plaintext
    message_cipher = message_plaintext
    
    # initial blinding_factor set to 1
    blinding_factor = Bn(1)
    
    # append first public key to list
    blinding_keys.append(public_keys[0])
    length = len(public_keys)
    
    for i in range(1, length):
        # generate shared element
        shared = private_key * blinding_keys[-1]
        material = sha512(shared.export()).digest()
        
        # generate another bliding factor
        blinding_factor = blinding_factor * Bn.from_binary(material[48:])
        
        # calculate and append blinding factor to a list
        public_key = public_keys[i]
        blinding_keys = blinding_keys + [blinding_factor * public_key]
    
    # In reverse order calculate message for each hop using generated blinding factors
    blinding_keys = reversed(blinding_keys)
    for key in blinding_keys:
        # generate shared element
        shared = private_key * key
        material = sha512(shared.export()).digest()
        
        # split shared key for different operations
        hmac_key = material[:16]
        address_key = material[16:32]
        message_key = material[32:48]
        
        # random inistialisation vector
        iv = b"\x00"*16
    
        # encoding address and message
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)
        
        # temporary list of hmacs
        temp_hmacs = []
        h = Hmac(b"sha512", hmac_key)
        
        for i in range(0,len(hmacs)):
            prev_mac = hmacs[i]
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00"*14)
            
            # encode
            hmac_plaintext = aes_ctr_enc_dec(hmac_key, iv, prev_mac)
            # add the encoded hmac to the temporary list
            temp_hmacs = temp_hmacs + [hmac_plaintext]
            h.update(hmac_plaintext)
    
        h.update(address_cipher)
        h.update(message_cipher)
        
        # turn h into binary
        expected_mac = h.digest()
        # take first 20 bits
        expected_mac = expected_mac[:20]
        # insert expected_mac (final mac) to the beggining of the list
        temp_hmacs = [expected_mac] + temp_hmacs
        
        # update hmacs list with temp_hmacs list
        hmacs = temp_hmacs
        
    return NHopMixMessage(client_public_key, hmacs, address_cipher, message_cipher)
Пример #11
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    iv = b"\x00" * 16

    # caluculate the blinding factor of all the
    # hops, can't be done during hmacs as it's in a different order.
    #
    blind_factors = []
    shared_keys = []
    for i, k in enumerate(public_keys):
        if i == 0:
            blind_factors.append(1)
        else:

            pub_key = public_keys[i - 1]

            # The shared key that the hop will use to calculate the factor
            shared_key = shared_keys[i - 1]
            key_digest = sha512(shared_key).digest()
            # the blinding factor that they will use
            blinding_factor = Bn.from_binary(key_digest[48:])
            blind_factors.append(blinding_factor)

        shared_key = public_keys[i].pt_mul(private_key)
        for j, fac in enumerate(blind_factors[0:i + 1]):
            shared_key = shared_key.pt_mul(blind_factors[j])
        shared_key = shared_key.export()
        shared_keys.append(shared_key)

    ## Reverse the key lists, since we will compute hmacs in reverse order
    shared_keys.reverse()
    public_keys.reverse()

    message_ciphers = []
    address_ciphers = []
    hmacs = []

    previous_hmac_key = None
    for i, pub in enumerate(public_keys):
        # Get shared key from precomputed list
        shared_key = shared_keys[i]
        key_digest = sha512(shared_key).digest()
        address_key = key_digest[16:32]
        message_key = key_digest[32:48]
        hmac_key = key_digest[:16]
        ## 1. Encrypt The Message
        if i == 0:
            message_cipher = aes_ctr_enc_dec(message_key, iv,
                                             message_plaintext)
            address_cipher = aes_ctr_enc_dec(address_key, iv,
                                             address_plaintext)
        else:
            message_cipher = aes_ctr_enc_dec(message_key, iv,
                                             message_ciphers[i - 1])
            address_cipher = aes_ctr_enc_dec(address_key, iv,
                                             address_ciphers[i - 1])
        message_ciphers.append(message_cipher)
        address_ciphers.append(address_cipher)

        ## 2. Encrypt the old HMACs
        for q, mac in enumerate(hmacs):
            iv = pack("H14s", len(hmacs) - q - 1, b"\x00" * 14)
            hmacs[q] = aes_ctr_enc_dec(hmac_key, iv, mac)

        previous_hmac_key = hmac_key

        ## 3. Compute the new HMAC
        h = Hmac(b"sha512", hmac_key)

        ## Iterate backwards through the previous hmacs
        for old_mac in hmacs[::-1]:
            h.update(old_mac)
        h.update(address_ciphers[i])
        h.update(message_ciphers[i])

        new_mac = h.digest()

        hmacs.append(new_mac[:20])

    # Hmacs were built in reverse order, put them back in order
    hmacs.reverse()

    return NHopMixMessage(client_public_key, hmacs,
                          address_ciphers[len(address_ciphers) - 1],
                          message_ciphers[len(message_ciphers) - 1])
Пример #12
0
def mix_server_n_hop(private_key, message_list, final=False):
    """ Decodes a NHopMixMessage message and outputs either messages destined
    to the next mix or a list of tuples (address, message) (if final=True) to be 
    sent to their final recipients.
    Broadly speaking the mix will process each message in turn: 
        - it derives a shared key (using its private_key), 
        - checks the first hmac,
        - decrypts all other parts,
        - either forwards or decodes the message. 
    """

    G = EcGroup()

    out_queue = []

    # Process all messages
    for msg in message_list:

        ## Check elements and lengths
        if not G.check_point(msg.ec_public_key) or \
               not isinstance(msg.hmacs, list) or \
               not len(msg.hmacs[0]) == 20 or \
               not len(msg.address) == 258 or \
               not len(msg.message) == 1002:
            raise Exception("Malformed input message")

        ## First get a shared key
        shared_element = private_key * msg.ec_public_key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        # Extract a blinding factor for the public_key
        blinding_factor = Bn.from_binary(key_material[48:])
        new_ec_public_key = blinding_factor * msg.ec_public_key

        ## Check the HMAC
        h = Hmac(b"sha512", hmac_key)

        for other_mac in msg.hmacs[1:]:
            h.update(other_mac)

        h.update(msg.address)
        h.update(msg.message)

        expected_mac = h.digest()

        if not secure_compare(msg.hmacs[0], expected_mac[:20]):
            raise Exception("HMAC check failure")

        ## Decrypt the hmacs, address and the message
        aes = Cipher("AES-128-CTR")

        # Decrypt hmacs
        new_hmacs = []
        for i, other_mac in enumerate(msg.hmacs[1:]):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00" * 14)

            hmac_plaintext = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            new_hmacs += [hmac_plaintext]

        # Decrypt address & message
        iv = b"\x00" * 16

        address_plaintext = aes_ctr_enc_dec(address_key, iv, msg.address)
        message_plaintext = aes_ctr_enc_dec(message_key, iv, msg.message)

        if final:
            # Decode the address and message
            address_len, address_full = unpack("!H256s", address_plaintext)
            message_len, message_full = unpack("!H1000s", message_plaintext)

            out_msg = (address_full[:address_len], message_full[:message_len])
            out_queue += [out_msg]
        else:
            # Pass the new mix message to the next mix
            out_msg = NHopMixMessage(new_ec_public_key, new_hmacs,
                                     address_plaintext, message_plaintext)
            out_queue += [out_msg]

    return out_queue
Пример #13
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 
    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    # ! = Network byte order, H = unsigned short, 256s = string 256 chars long
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    ## ADD CODE HERE
    key_materials = []
    private_keys = [private_key]

    ## Create the shared elements and key materials for each of the hops,
    ## by iterating through the list of public keys provided
    for i, hop_public_key in enumerate(public_keys):

        ## First get a shared key for each mix
        shared_element = private_keys[i] * hop_public_key
        key_material = sha512(shared_element.export()).digest()
        key_materials.append(key_material)

        ## Extract a blinding factor for this key material
        blinding_factor = Bn.from_binary(key_material[48:])

        ## Get a new private key using the blinding factor for the next mix
        new_ec_private_key = blinding_factor * private_keys[i]
        private_keys.append(new_ec_private_key)

    ## Initialization
    address_cipher = address_plaintext
    message_cipher = message_plaintext

    hmacs = []

    ## This iteration needs to happen in reverse, as we need to "encapsulate"
    ## the information for the last hop in the info for the second to last etc.
    counter = 0
    for i, key_material in reversed(list(enumerate(key_materials))):

        ## Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        ## Encrypt the address and the message
        iv = b"\x00" * 16
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        ## Create HMAC
        h = Hmac(b"sha512", hmac_key)
        print(len(key_materials) - i - 1)
        ## Encrypt other mac for the mixes after the current one
        for j, other_mac in enumerate(hmacs[:counter]):
            ## iv different for each mac
            iv = pack("H14s", j, b"\x00" * 14)
            hmac_cipher = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            ## Add this cipher to the HMAC for the current mix
            h.update(hmac_cipher)
            ## Replace the HMAC for the mixes after the current one by their cipher
            hmacs.pop(j)
            hmacs.insert(j, hmac_cipher)

        ## Add the address and message cipher to the HMAC
        h.update(address_cipher)
        h.update(message_cipher)

        ## Insert the HMAC at the list top
        expected_mac = h.digest()[:20]
        hmacs.insert(0, expected_mac)
        counter += 1

    print('Client: ', hmacs)
    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #14
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    # Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()
    hmacs = []
    blinding_factor = Bn(1)
    new_pub_keys = []

    # Get a list of new blinded public keys
    counter = 0
    for key in public_keys:
        if counter == 0:
            new_pub_keys.append(key)
        else:
            shared_element = private_key * new_pub_keys[-1]
            shared_key = sha512(shared_element.export()).digest()
            blinding_factor *= Bn.from_binary(shared_key[48:])
            new_key = blinding_factor * key
            new_pub_keys.append(new_key)
        counter += 1

    #reverse the list as you start encrypting from last hop       
    new_pub_keys.reverse()
    address_cipher = address_plaintext
    message_cipher = message_plaintext

    for pub_key in new_pub_keys:
        # Generate Keying Material
        new_shared_material = private_key * pub_key
        new_shared_key = sha512(new_shared_material.export()).digest()

        # Calculate Other Keys
        hmac_key = new_shared_key[:16]
        address_key = new_shared_key[16:32]
        message_key = new_shared_key[32:48]

        iv = b"\x00"*16
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        decrypted_hmacs = []
        h = Hmac(b"sha512", hmac_key)

        # Decrypt HMACs and update them
        for i,other_hmac in enumerate(hmacs):
            hmac_iv = pack("H14s", i, b"\x00"*14)
            decrypted_hmac = aes_ctr_enc_dec(hmac_key, hmac_iv, other_hmac)
            h.update(decrypted_hmac)
            decrypted_hmacs.append(decrypted_hmac)

        # Update HMAC of message and cipher     
        h.update(address_cipher)
        h.update(message_cipher)
        expected_hmac = h.digest()[:20]

        # Add new HMACs to list

        hmacs = [expected_hmac] + decrypted_hmacs

    ## ADD CODE HERE

    return NHopMixMessage(client_public_key, hmacs, address_cipher, message_cipher)
Пример #15
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys.
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes).

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_cipher = pack("!H256s", len(address), address)
    message_cipher = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    hmacs = []
    key_materials = []
    """
    We need to precompute the private keys that we're going to be use considering
    the Blinding Factor. Encryption is back to front but Blinding factor is front to back,
    that's why we need to do this in advance.
    """
    for pk_i, public_key in enumerate(public_keys):
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        key_materials.append(key_material)

        # Apply blinding factor to private key for the next shared key derivation
        blinding_factor = Bn.from_binary(key_material[48:])
        private_key *= blinding_factor
    """
    Iterate list back to front so that encryption is done in correct order.
    """
    for i, public_key in enumerate(reversed(public_keys)):
        shared_element = private_key * public_key
        key_material = key_materials[-(i + 1)]

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        ## Encrypt
        iv = b"\x00" * 16
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        def enc_hmac((index, hmac)):
            iv = pack("H14s", index, b"\x00" * 14)
            return aes_ctr_enc_dec(hmac_key, iv, hmac)

        hmacs = map(enc_hmac, enumerate(hmacs))

        ## Generate HMAC
        h = Hmac(b"sha512", hmac_key)
        for other_hmac in hmacs:
            h.update(other_hmac)
        h.update(address_cipher)
        h.update(message_cipher)

        expected_mac = h.digest()[:20]

        hmacs.insert(0, expected_mac)

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #16
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys.
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes).

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    address_cipher = address_plaintext
    message_cipher = message_plaintext
    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()

    ## ADD CODE HERE
    ###Initialise blinding factor and blindking keys
    blinding_factor = Bn(1)
    blinding_keys=[]
    ##initialise Hmacs array
    hmacs = []

    ###start from second key as first key is not blinded in the mix
    for i in range(len(public_keys)):

        ###first key is not blinded so since blinding
        public_key = blinding_factor*public_keys[i]
        blinding_keys.append(public_key)

        ##
        shared_element = private_key * blinding_keys[i]
        key_material = sha512(shared_element.export()).digest()

        blinding_factor *= Bn.from_binary(key_material[48:])

    ### reverse order as you encrypt from last mix first
    for k in reversed(blinding_keys):

        ##shared element
        shared_element = private_key * k
        key_material = sha512(shared_element.export()).digest()

        ###produce keys for hmac address and message
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        ##assign iv for ciphers and encyrpt
        iv = b"\x00" * 16
        address_cipher = aes_ctr_enc_dec(address_key,iv,address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key,iv,message_cipher)

        h = Hmac(b"sha512",hmac_key)## initialise hmac
        ####produce hmacs
        temp = []


        for j,other in enumerate(hmacs):

            ###seperate iv for each hmac
            iv = pack("H14s",j,b"\x00"*14)
            hmac_plaintext = aes_ctr_enc_dec(hmac_key,iv,other)
            temp+=[hmac_plaintext]
            h.update(hmac_plaintext)

        h.update(address_cipher)
        h.update(message_cipher)

        expected_mac = h.digest()[:20]
        temp =[expected_mac]+temp
        hmacs=temp
    return NHopMixMessage(client_public_key, hmacs, address_cipher, message_cipher)
Пример #17
0
def mix_server_n_hop(private_key, message_list, use_blinding_factor=False, final=False):
    """ Decodes a NHopMixMessage message and outputs either messages destined
    to the next mix or a list of tuples (address, message) (if final=True) to be 
    sent to their final recipients.

    Broadly speaking the mix will process each message in turn: 
        - it derives a shared key (using its private_key), 
        - checks the first hmac,
        - decrypts all other parts,
        - Either forwards or decodes the message. 

    The implementation of the blinding factor is optional and therefore only activated 
    in the bonus tests.
    """

    G = EcGroup()

    out_queue = []

    # Process all messages
    for msg in message_list:

        ## Check elements and lengths
        if not G.check_point(msg.ec_public_key) or \
               not isinstance(msg.hmacs, list) or \
               not len(msg.hmacs[0]) == 20 or \
               not len(msg.address) == 258 or \
               not len(msg.message) == 1002:
           raise Exception("Malformed input message")

        ## First get a shared key
        shared_element = private_key * msg.ec_public_key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        # Extract a blinding factor for the public_key 
        # (only if you're brave enough for the bonus task)
        new_ec_public_key = msg.ec_public_key
        if (use_blinding_factor):
            blinding_factor = Bn.from_binary(key_material[48:])
            new_ec_public_key = blinding_factor * msg.ec_public_key

        ## Check the HMAC
        h = Hmac(b"sha512", hmac_key)

        for other_mac in msg.hmacs[1:]:
            h.update(other_mac)

        h.update(msg.address)
        h.update(msg.message)

        expected_mac = h.digest()

        if not secure_compare(msg.hmacs[0], expected_mac[:20]):
            raise Exception("HMAC check failure")

        # Decrypt hmacs
        new_hmacs = []
        for i, other_mac in enumerate(msg.hmacs[1:]):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00"*14)

            hmac_plaintext = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            new_hmacs += [hmac_plaintext]

        # Decrypt address & message
        iv = b"\x00"*16
        
        address_plaintext = aes_ctr_enc_dec(address_key, iv, msg.address)
        message_plaintext = aes_ctr_enc_dec(message_key, iv, msg.message)

        if final:
            # Decode the address and message
            address_len, address_full = unpack("!H256s", address_plaintext)
            message_len, message_full = unpack("!H1000s", message_plaintext)

            out_msg = (address_full[:address_len], message_full[:message_len])
            out_queue += [out_msg]
        else:
            # Pass the new mix message to the next mix
            out_msg = NHopMixMessage(new_ec_public_key, new_hmacs, address_plaintext, message_plaintext)
            out_queue += [out_msg]

    return out_queue
Пример #18
0
def mix_client_n_hop(public_keys, address, message, use_blinding_factor=False):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    The implementation of the blinding factor is optional and therefore only activated 
    in the bonus tests. It can be ignored for the standard task.
    If you implement the bonus task make sure to only activate it if use_blinding_factor is True.
    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()

    #TODO ADD CODE HERE
    hmacs = []
    keys_count = len(public_keys)
    
    for i in range(keys_count-1,-1,-1):
	new_macs = []	
	key = public_keys[i]

        encryption_key = private_key * key
        ek = sha512(encryption_key.export()).digest()        
	
        #get coresponding key parts	
        hmac_key = ek[:16]
        address_key = ek[16:32]
        message_key = ek[32:48]
	
        #encrypt for this hop
        iv = b"\x00"*16	
	
	if (i == keys_count-1): # last hop before destination
        	address_cipher = aes_ctr_enc_dec(address_key, iv, address_plaintext)            
        	message_cipher = aes_ctr_enc_dec(message_key, iv, message_plaintext)
	else:
        	address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)            
        	message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)		

        #calculate mac for this hop        
        h = Hmac(b"sha512", hmac_key)
	
	        		
	if(len(hmacs)>0):	
       	    for i, other_mac in enumerate(hmacs):
                # Ensure the IV is different for each hmac
                iv = pack("H14s", i, b"\x00"*14)
                hmac_enc = aes_ctr_enc_dec(hmac_key, iv, other_mac)
	    	h.update(hmac_enc)	
                new_macs.append(hmac_enc)	

	h.update(address_cipher)
        h.update(message_cipher)
        expected_mac = h.digest()
	expected_mac = expected_mac[:20]	
	
	#print "server hmac_key  : ", hmac_key
	#print "client addr_key  : ", address_key
	#print "server mesg_key  : ", message_key

	#print "client adr_cipher: ", address_cipher[:75]
	#print "client msg_cipher: ", message_cipher[:75]
	
	new_macs.insert(0,expected_mac)
	hmacs = new_macs
	#print "client client_mac: ", expected_mac
		
    return NHopMixMessage(client_public_key, hmacs, address_cipher, message_cipher)
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    # initilise lists for hmacs and blinding_keys
    hmacs = []
    blinding_keys = []

    # initilise variables
    address_cipher = address_plaintext
    message_cipher = message_plaintext

    # initial blinding_factor set to 1
    blinding_factor = Bn(1)

    # append first public key to list
    blinding_keys.append(public_keys[0])
    length = len(public_keys)

    for i in range(1, length):
        # generate shared element
        shared = private_key * blinding_keys[-1]
        material = sha512(shared.export()).digest()

        # generate another bliding factor
        blinding_factor = blinding_factor * Bn.from_binary(material[48:])

        # calculate and append blinding factor to a list
        public_key = public_keys[i]
        blinding_keys = blinding_keys + [blinding_factor * public_key]

    # In reverse order calculate message for each hop using generated blinding factors
    blinding_keys = reversed(blinding_keys)
    for key in blinding_keys:
        # generate shared element
        shared = private_key * key
        material = sha512(shared.export()).digest()

        # split shared key for different operations
        hmac_key = material[:16]
        address_key = material[16:32]
        message_key = material[32:48]

        # random inistialisation vector
        iv = b"\x00" * 16

        # encoding address and message
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        # temporary list of hmacs
        temp_hmacs = []
        h = Hmac(b"sha512", hmac_key)

        for i in range(0, len(hmacs)):
            prev_mac = hmacs[i]
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00" * 14)

            # encode
            hmac_plaintext = aes_ctr_enc_dec(hmac_key, iv, prev_mac)
            # add the encoded hmac to the temporary list
            temp_hmacs = temp_hmacs + [hmac_plaintext]
            h.update(hmac_plaintext)

        h.update(address_cipher)
        h.update(message_cipher)

        # turn h into binary
        expected_mac = h.digest()
        # take first 20 bits
        expected_mac = expected_mac[:20]
        # insert expected_mac (final mac) to the beggining of the list
        temp_hmacs = [expected_mac] + temp_hmacs

        # update hmacs list with temp_hmacs list
        hmacs = temp_hmacs

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #20
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    ## ADD CODE HERE
    # Initialize list of key_material
    key_material_list = []

    # Iterate the list of public keys
    for public_key in public_keys:
        # Get shared key
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # Insert at the head of the list
        key_material_list.insert(0, key_material)

        # Extract a blinding factor for the public_key
        blinding_factor = Bn.from_binary(key_material[48:])

        # Change key using blinding factor
        private_key *= blinding_factor

    # Initialize
    hmacs = []
    address_cipher = address_plaintext
    message_cipher = message_plaintext

    # Iterate the public keys in reverse order
    for i, public_key in enumerate(public_keys[::-1]):
        # Use different parts of the shared key for different operations
        hmac_key = key_material_list[i][:16]
        address_key = key_material_list[i][16:32]
        message_key = key_material_list[i][32:48]

        # Encrypt address & message
        iv = b"\x00" * 16

        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        # Generate HMAC
        h = Hmac(b"sha512", hmac_key)

        # Generate new hmacs
        for i, hmac in enumerate(hmacs):
            iv = pack("H14s", i, b"\x00" * 14)
            new_hmac = aes_ctr_enc_dec(hmac_key, iv, hmac)
            hmacs[i] = new_hmac
            h.update(hmacs[i])

        h.update(address_cipher)
        h.update(message_cipher)

        hmac = h.digest()[:20]
        hmacs.insert(0, hmac)

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #21
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    shared_keys = []

    # PART 1
    # use of a blinding factor to provide bit-wise unlikability of
    # the public key associated with the message
    for public_key in public_keys:
        # get a shared key
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # store into list from back to front
        shared_keys = [key_material] + shared_keys

        # update private key value of client with a blinding factor for next shared key derivation
        private_key = private_key * Bn.from_binary(key_material[48:])

    address_cipher = address_plaintext
    message_cipher = message_plaintext

    # PART 2
    # inclusion of a (list) of hmacs as the second part of the mix message
    # done in reverse order to compute hmacs
    hmacs = []
    for i, public_key in enumerate(reversed(shared_keys)):

        # Use different parts of the shared key for different operations
        hmac_key = shared_keys[i][:16]
        address_key = shared_keys[i][16:32]
        message_key = shared_keys[i][32:48]

        # Ecrypt the address and the message
        iv = b"\x00" * 16

        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        # Check HMAC
        h = Hmac(b"sha512", hmac_key)

        # PART 3
        # Encryption of the hmacs (in addition to the address and message) at each step of mixing

        # loop skipped on first call
        for j, other_hmac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", j, b"\x00" * 14)
            hmacs[j] = aes_ctr_enc_dec(hmac_key, iv, other_hmac)
            h.update(hmacs[j])

        h.update(address_cipher)
        h.update(message_cipher)

        hmacs = [h.digest()[:20]] + hmacs  ## add result to hmacs list

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #22
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    ## ADD CODE HERE
    # Generate key materials
    key_materials = []
    next_blinding_factor = None
    for pubkey in public_keys:
        shared_element = None
        if not next_blinding_factor is None:
            private_key *= next_blinding_factor

        shared_element = private_key * pubkey
        key_material = sha512(shared_element.export()).digest()

        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        next_blinding_factor = Bn.from_binary(key_material[48:])

        key_materials += [(hmac_key, address_key, message_key)]

    new_hmacs = []
    address_cipher = bytes(address_plaintext)
    message_cipher = bytes(message_plaintext)
    for i, key_material in reversed(list(enumerate(key_materials))):
        # Encrypt the address and the message
        iv = b"\x00" * 16

        address_cipher = aes_ctr_enc_dec(key_material[1], iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(key_material[2], iv, message_cipher)

        # Encrypt the HMACs
        for i, hmac in enumerate(new_hmacs):
            iv = pack("H14s", i, b"\x00" * 14)
            new_hmacs[i] = aes_ctr_enc_dec(key_material[0], iv, hmac)

        # Compute the HMAC
        h = Hmac(b"sha512", key_material[0])
        for hmac in new_hmacs:
            h.update(hmac)
        h.update(address_cipher)
        h.update(message_cipher)
        new_hmac = h.digest()[:20]

        new_hmacs = [new_hmac] + new_hmacs

    return NHopMixMessage(client_public_key, new_hmacs, address_cipher,
                          message_cipher)
Пример #23
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys.
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes).
    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    # Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    shared_keys = []
    hmacs = []

    # no blinding factor between Alice and the first mix
    new_private_key = private_key
    # the first ciphertext is the plaintext
    address_cipher = address_plaintext
    message_cipher = message_plaintext

    # generate new private key for each mix's public key
    for public_key in public_keys:
        # get a shared key
        shared_element = new_private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # prepend the shared key to the list of shared keys
        shared_keys = [key_material] + shared_keys

        # update the private key's value with a blinding factor
        new_private_key = new_private_key * Bn.from_binary(key_material[48:])

    # iterate through the public keys in the reverse order, because we want
    # to compute hmacs in the reverse order
    for i, public_key in enumerate(public_keys[::-1]):

        # Use different parts of the shared key for different operations
        hmac_key = shared_keys[i][:16]
        address_key = shared_keys[i][16:32]
        message_key = shared_keys[i][32:48]

        # Decrypt the address and the message
        iv = b"\x00" * 16
        # we encrypt the ciphertext
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        # Create the HMAC
        h = Hmac(b"sha512", hmac_key)

        # encrypt the known hmacs
        for j, hmac in enumerate(hmacs):
            # Ensure the IV is different for each hmac and encode it
            iv = pack("H14s", j, b"\x00" * 14)
            hmacs[j] = aes_ctr_enc_dec(hmac_key, iv, hmac)
            h.update(hmacs[j])

        # finish building the hmac
        h.update(address_cipher)
        h.update(message_cipher)
        # prepend the result to the list of hmacs
        hmacs = [h.digest()[:20]] + hmacs

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    address_cipher = None
    message_cipher = None

    hmacs = []

    blinded_public_keys = [public_keys[0]]

    blinding_factor = Bn(1)

    for public_key in public_keys[1:]:
        ## First get a shared key
        shared_element = private_key * blinded_public_keys[-1]
        key_material = sha512(shared_element.export()).digest()
        blinding_factor *= Bn.from_binary(key_material[48:])
        blind_pk = blinding_factor * public_key
        blinded_public_keys.append(blind_pk)

    blinded_public_keys.reverse()

    for public_key in blinded_public_keys:
        # ## First get a shared key

        # Get a shared key
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        h = Hmac(b"sha512", hmac_key)
        for other_mac in hmacs:
            h.update(other_mac)

        if address_cipher is None:
            address_cipher = aes_ctr_enc_dec(address_key, b'\x00' * 16,
                                             address_plaintext)
        else:
            address_cipher = aes_ctr_enc_dec(address_key, b'\x00' * 16,
                                             address_cipher)

        if message_cipher is None:
            message_cipher = aes_ctr_enc_dec(message_key, b'\x00' * 16,
                                             message_plaintext)
        else:
            message_cipher = aes_ctr_enc_dec(message_key, b'\x00' * 16,
                                             message_cipher)

        h.update(address_cipher)
        h.update(message_cipher)
        mac = h.digest()[:20]
        hmacs.append(mac)

    hmacs.reverse()

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #25
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # This assertion was originally commented out, can instead check each of the keys one by one
    for public_key in public_keys:
        assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    ## ADD CODE HERE
    # Calculate shared keys, taking into account blinding
    shared_elems = []
    blinded = []

    new = public_keys[0]
    for i, public_key in enumerate(public_keys):

        shared = private_key * new
        shared_elems.append(shared)
        if i == len(public_keys) - 1:
            break

        key_material = sha512(shared.export()).digest()
        blinding = Bn.from_binary(key_material[48:])
        blinded.append(blinding)

        blind = blinded[0]
        for b in range(len(blinded[1:])):
            blind = blind * blinded[b + 1]
        new = blind * public_keys[i + 1]

    # Shared keys are used 'backwards'
    shared_elems.reverse()
    public_keys.reverse()

    # At the start of the encryption chain, the payload is in plaintext
    address_cipher = address_plaintext
    message_cipher = message_plaintext

    # Perform the encoding at each stage, using the shared elements calculated
    hmacs = []
    for i, public_key in enumerate(public_keys):

        shared_element = shared_elems[i]

        # Get the appropriate key from each part of the shared key
        key_material = sha512(shared_element.export()).digest()
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        # Encrypt the message and address at each stage
        iv = b"\x00" * 16
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        # Encrypt the hmacs at each stage
        for j, hm in enumerate(hmacs):
            iv = pack("H14s", j, b"\x00" * 14)
            hmac_plaintext = aes_ctr_enc_dec(key_material[:16], iv, hm)
            hmacs[j] = hmac_plaintext

        # Generate the expected mac for each stage
        h = Hmac(b"sha512", hmac_key)
        for hm in hmacs:
            h.update(hm)
        h.update(address_cipher)
        h.update(message_cipher)
        expected_mac = h.digest()[:20]

        # Each hmac is inserted at the start of the list, as the last hmac is the first to be
        # inspected - the last encryption is also the first to be decrypted
        hmacs.insert(0, expected_mac)

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #26
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 
    """
    G = EcGroup()
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    hmacs = []
    new_public_keys = []
    # process the keys with blinding_factor
    blinding_factor = Bn(1)
    for public_key in public_keys:
        public_key = blinding_factor * public_key
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # Extract a blinding factor for the public_key
        blinding_factor *= Bn.from_binary(key_material[48:])
        new_public_keys.insert(
            0, public_key)  # we need to encode messages in reverse order

    address_cipher = address_plaintext
    message_cipher = message_plaintext

    for public_key in new_public_keys:
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]
        # Decrypt address & message
        iv = b"\x00" * 16

        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        # Check the HMAC
        h = Hmac(b"sha512", hmac_key)

        # Decrypt hmacs
        new_hmacs = []
        for i, other_mac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00" * 14)

            hmac_plaintext = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            new_hmacs += [hmac_plaintext]
            h.update(hmac_plaintext)

        h.update(address_cipher)
        h.update(message_cipher)

        expected_mac = h.digest()[:20]

        hmacs = new_hmacs
        hmacs.insert(0, expected_mac)

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #27
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    ## ADD CODE HERE
    hmacs = []
    shared_keys = []

    ## generate all used shared key
    for public_key in public_keys:

        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        ## Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        ## Extract a blinding factor for next private_key
        blinding_factor = Bn.from_binary(key_material[48:])
        private_key = blinding_factor * private_key

        shared_keys.append([hmac_key, address_key, message_key])

    for shared_key in reversed(shared_keys):

        ## get the shared key
        hmac_key, address_key, message_key = shared_key[0], shared_key[
            1], shared_key[2]

        ## Encrypt the address and the message
        iv = b"\x00" * 16

        address_cipher = aes_ctr_enc_dec(address_key, iv, address_plaintext)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_plaintext)

        address_plaintext = address_cipher
        message_plaintext = message_cipher

        ## HMAC
        new_hmacs = []
        h = Hmac(b"sha512", hmac_key)

        # Encrypt hmacs
        for i, hmac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00" * 14)
            hmac_ciphertext = aes_ctr_enc_dec(hmac_key, iv, hmac)
            h.update(hmac_ciphertext)
            new_hmacs += [hmac_ciphertext]

        h.update(address_cipher)
        h.update(message_cipher)
        hmac = h.digest()[:20]
        new_hmacs.insert(0, hmac)

        hmacs = new_hmacs

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #28
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    hmacs = []
    address_cipher = address_plaintext
    message_cipher = message_plaintext

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    blinding_factor = Bn(1)
    new_ec_public_keys = []

    ## ADD CODE HERE
    i = 0
    for public_key in public_keys:
        # We don't want to blind the first key
        if i == 0:
            new_ec_public_keys.append(public_key)
        else:
            ## First get a shared key
            ## public key part is the last seen public key
            shared_element = private_key * new_ec_public_keys[-1]
            key_material = sha512(shared_element.export()).digest()

            # Building up list of all public keys  - they have been blinded
            blinding_factor *= Bn.from_binary(key_material[48:])
            new_ec_public_keys.append(blinding_factor * public_key)
        i += 1

    # Want to encrypt message with the first mix's key on the outside - reverse our public keys for this
    for key in reversed(new_ec_public_keys):
        ## First get a shared key
        shared_element = private_key * key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        iv = b"\x00" * 16
        # Build cipher on top of cipher from last mix to create message such as P1(P2(P3...(M)...))
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        ## Check the HMAC
        h = Hmac(b"sha512", hmac_key)

        # Decrypt hmacs
        new_hmacs = []
        for i, other_mac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00" * 14)
            hmac_plaintext = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            h.update(hmac_plaintext)
            new_hmacs += [hmac_plaintext]

        h.update(address_cipher)
        h.update(message_cipher)
        expected_mac = h.digest()[:20]

        hmacs = [expected_mac] + new_hmacs

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #29
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()

    # Get list of private keys multiplied with bliding factors
    private_keys = list()
    for public_key in public_keys:
        # Add private key to list
        private_keys.append(private_key)

        # Get shared key
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # Extract a blinding factor for the private_key
        blinding_factor = Bn.from_binary(key_material[48:])
        private_key = blinding_factor * private_key

    hmacs = list()
    address_cipher = address_plaintext
    message_cipher = message_plaintext
    for private_key, public_key in reversed(zip(private_keys, public_keys)):
        # Get shared key
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        # Encrypt address & message
        iv = b"\x00"*16
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        # Generate next HMAC and encrypt previous HMACs
        h = Hmac(b"sha512", hmac_key)
        for i in range(0, len(hmacs)):
            iv = pack("H14s", i, b"\x00"*14)
            hmacs[i] = aes_ctr_enc_dec(hmac_key, iv, hmacs[i])
            h.update(hmacs[i])
        h.update(address_cipher)
        h.update(message_cipher)
        expected_mac = h.digest()[:20]
        hmacs.insert(0, expected_mac)

    return NHopMixMessage(client_public_key, hmacs, address_cipher, message_cipher)
Пример #30
0
def mix_client_n_hop(public_keys, address, message, use_blinding_factor=False):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    The implementation of the blinding factor is optional and therefore only activated 
    in the bonus tests. It can be ignored for the standard task.
    If you implement the bonus task make sure to only activate it if use_blinding_factor is True.
    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()
    #TODO ADD CODE HERE
    hmacs = []
    address_cipher = address_plaintext
    message_cipher = message_plaintext
    for public_key in reversed(public_keys):
        new_hmacs = []
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]
        # Encrypt address & message
        iv = b"\x00" * 16
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        for i, other_mac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00" * 14)

            hmac_cipher = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            new_hmacs.append(hmac_cipher)
        hmacs = list(reversed(new_hmacs))

        h = Hmac(b"sha512", hmac_key)

        for other_mac in reversed(hmacs):
            h.update(other_mac)

        h.update(address_cipher)
        h.update(message_cipher)

        expected_mac = h.digest()[:20]
        hmacs.append(expected_mac)
        hmacs.reverse()
    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #31
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()

    ## ADD CODE HERE
    shared_element = None
    address_cipher = None
    message_cipher = None
    hmacs = []
    hmackeys = []
    messkeys = []
    addkeys = []
    messciphers = []
    addciphers = []
    for i in range(len(public_keys)):
    	## First get a shared key                                                   #*
        shared_element = private_key * public_keys[i]
        key_material = sha512(shared_element.export()).digest()                  

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]                                                # This section: like the beginning of mix_server_n_hop
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        # Extract a blinding factor for the new private key
        blinding_factor = Bn.from_binary(key_material[48:])
        private_key = blinding_factor * private_key                                 #*

        # Add keys to corresponding arrays
        hmackeys += [hmac_key]
        addkeys += [address_key]
        messkeys += [message_key]


    for i in range(len(public_keys)):

    	# Encrypt address & message 
        iv = b"\x00"*16
        
        if i==0:
        	address_cipher = aes_ctr_enc_dec(addkeys[len(public_keys)-1-i], iv, address_plaintext)
        	message_cipher = aes_ctr_enc_dec(messkeys[len(public_keys)-1-i], iv, message_plaintext)
        else:
        	address_cipher = aes_ctr_enc_dec(addkeys[len(public_keys)-1-i], iv, address_cipher)
        	message_cipher = aes_ctr_enc_dec(messkeys[len(public_keys)-1-i], iv, message_cipher)

        messciphers += [message_cipher]
        addciphers += [address_cipher]


    for i in range(len(public_keys)):

        # Encryption of hmacs. Individual as we need whole ciphertext to compute macs correctly
        # Use mac keys in reverse as last ciphertext needs first key
        new_hmacs = []
        for j, other_mac in enumerate(hmacs):
            # Ensure IV is not the same for each hmac
            iv = pack("H14s", j, b"\x00"*14)

            hmac_plaintext = aes_ctr_enc_dec(hmackeys[len(public_keys)-1-i], iv, other_mac)
            new_hmacs += [hmac_plaintext]  


        h = Hmac(b"sha512", hmackeys[len(public_keys)-1-i])
        # Calculate new digest
        new_hmacs = new_hmacs[::-1]
        for other_mac in reversed(new_hmacs):
                h.update(other_mac) 

        h.update(addciphers[i])
        h.update(messciphers[i])
        
        digest  = h.digest()
        digest	= digest[:20]

        new_hmacs += [digest]
        hmacs = new_hmacs[::-1]

    hmacs = new_hmacs[::-1]

    return NHopMixMessage(client_public_key, hmacs, address_cipher, message_cipher)
Пример #32
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    ## Get shared keys (top-down)
    keyring = namedtuple("Keyring", ["hmac_key", "address_key", "message_key"])
    shared_keys = []
    accumulated_blinding_factor = Bn(1)
    for public_key in public_keys:
        shared_key = accumulated_blinding_factor * private_key * public_key
        key_material = sha512(shared_key.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]
        blinding_factor = Bn.from_binary(key_material[48:])
        accumulated_blinding_factor = accumulated_blinding_factor * blinding_factor

        # Store keyring
        shared_keys.append(keyring(hmac_key, address_key, message_key))

    ## Construct NHop message (bottom-up)
    hmacs = []
    address_cipher = address_plaintext
    message_cipher = message_plaintext
    for shared_key in reversed(shared_keys):
        # Encrypt address and message; accumulate
        iv = b"\x00" * 16
        address_cipher = aes_ctr_enc_dec(shared_key.address_key, iv,
                                         address_cipher)
        message_cipher = aes_ctr_enc_dec(shared_key.message_key, iv,
                                         message_cipher)

        # Encrypt other HMACs
        for i, hmac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00" * 14)
            hmacs[i] = aes_ctr_enc_dec(shared_key.hmac_key, iv, hmac)

        # Get HMAC
        h = Hmac(b"sha512", shared_key.hmac_key)
        for hmac in hmacs:
            h.update(hmac)
        h.update(address_cipher)
        h.update(message_cipher)
        expected_mac = h.digest()[:20]
        hmacs.insert(0, expected_mac)

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #33
0
def mix_client_n_hop(public_keys, address, message, use_blinding_factor=False):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    The implementation of the blinding factor is optional and therefore only activated 
    in the bonus tests. It can be ignored for the standard task.
    If you implement the bonus task make sure to only activate it if use_blinding_factor is True.
    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key  = private_key * G.generator()
    #TODO ADD CODE HERE
    hmacs = []
    address_cipher = address_plaintext
    message_cipher = message_plaintext
    for public_key in reversed(public_keys):
	new_hmacs = []
        shared_element = private_key * public_key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]
	# Encrypt address & message
        iv = b"\x00"*16
        address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

	for i, other_mac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", i, b"\x00"*14)

            hmac_cipher = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            new_hmacs.append(hmac_cipher)
	hmacs = list(reversed(new_hmacs))
	 
	h = Hmac(b"sha512", hmac_key)
	
        for other_mac in reversed(hmacs):
            h.update(other_mac)

        h.update(address_cipher)
        h.update(message_cipher)

        expected_mac = h.digest()[:20]
	hmacs.append(expected_mac)
	hmacs.reverse()
    return NHopMixMessage(client_public_key, hmacs, address_cipher, message_cipher)
Пример #34
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 
    """
    G = EcGroup()
    blinding_factor = Bn(1)
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000

    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    ## ADD CODE HERE

    hmacs = []

    address_cipher = address_plaintext
    message_cipher = message_plaintext

    blinded_public_keys = [public_keys[0]]

    for public_key in public_keys[1:]:
        ## First get a shared key
        shared_element = private_key * blinded_public_keys[-1]
        key_material = sha512(shared_element.export()).digest()
        blinding_factor *= Bn.from_binary(key_material[48:])
        blinded_public_keys.append(blinding_factor * public_key)

    for key in reversed(blinded_public_keys):
        ## First get a shared key
        shared_element = private_key * key
        key_material = sha512(shared_element.export()).digest()

        # Use different parts of the shared key for different operations
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        address_cipher = aes_ctr_enc_dec(address_key, b"\x00" * 16,
                                         address_cipher)
        message_cipher = aes_ctr_enc_dec(message_key, b"\x00" * 16,
                                         message_cipher)

        ## Check the HMAC
        h = Hmac(b"sha512", hmac_key)

        # implement hmacs
        new_hmacs = []
        for i, other_mac in enumerate(hmacs):
            # Ensure the IV is different for each hmac
            hmac_plaintext = aes_ctr_enc_dec(hmac_key,
                                             pack("H14s", i, b"\x00" * 14),
                                             other_mac)
            h.update(hmac_plaintext)
            new_hmacs += [hmac_plaintext]

        h.update(address_cipher)
        h.update(message_cipher)
        expected_mac = h.digest()[:20]

        hmacs = [expected_mac] + new_hmacs

    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)
Пример #35
0
def mix_client_n_hop(public_keys, address, message):
    """
    Encode a message to travel through a sequence of mixes with a sequence public keys. 
    The maximum size of the final address and the message are 256 bytes and 1000 bytes respectively.
    Returns an 'NHopMixMessage' with four parts: a public key, a list of hmacs (20 bytes each),
    an address ciphertext (256 + 2 bytes) and a message ciphertext (1002 bytes). 

    """
    G = EcGroup()
    # assert G.check_point(public_key)
    assert isinstance(address, bytes) and len(address) <= 256
    assert isinstance(message, bytes) and len(message) <= 1000
    # Encode the address and message
    # use those encoded values as the payload you encrypt!
    address_plaintext = pack("!H256s", len(address), address)
    message_plaintext = pack("!H1000s", len(message), message)

    ## Generate a fresh public key
    private_key = G.order().random()
    client_public_key = private_key * G.generator()

    ## ADD CODE HERE
    address_cipher = None
    message_cipher = None
    hmacs = []
    key_materials = []

    # We loop once to generate the blinded keys and corresponding key_materials
    for i in range(len(public_keys)):
        # Generate the encryption key
        shared_element = private_key * public_keys[i]
        key_material = sha512(shared_element.export()).digest()

        # Add the key generated with the blindness added since private key gets overriden
        key_materials += [key_material]

        # Extract a blinding factor for the public_key
        blinding_factor = Bn.from_binary(key_material[48:])
        private_key = blinding_factor * private_key

    # Reverse the calculated key_materials for correct ordering as per the server
    key_materials = key_materials[::-1]

    for i in range(len(public_keys)):
        key_material = key_materials[i]
        hmac_key = key_material[:16]
        address_key = key_material[16:32]
        message_key = key_material[32:48]

        iv = b"\x00" * 16
        # First we want to encrypt the plaintext, then it will be the ciphertext
        if i == 0:
            address_cipher = aes_ctr_enc_dec(address_key, iv,
                                             address_plaintext)
            message_cipher = aes_ctr_enc_dec(message_key, iv,
                                             message_plaintext)
        else:
            address_cipher = aes_ctr_enc_dec(address_key, iv, address_cipher)
            message_cipher = aes_ctr_enc_dec(message_key, iv, message_cipher)

        new_hmacs = []
        for j, other_mac in enumerate(reversed(hmacs)):
            # Ensure the IV is different for each hmac
            iv = pack("H14s", j, b"\x00" * 14)

            hmac_plaintext = aes_ctr_enc_dec(hmac_key, iv, other_mac)
            new_hmacs += [hmac_plaintext]

        h = Hmac(b"sha512", hmac_key)
        new_hmacs = new_hmacs[::-1]

        # Add all other macs plus the address and message cipher to the hmac
        for other_mac in reversed(new_hmacs):
            h.update(other_mac)
        h.update(address_cipher)
        h.update(message_cipher)

        # take only the first 20 bytes
        digest = h.digest()[:20]

        # Add the calculated hmac
        new_hmacs += [digest]

        hmacs = new_hmacs

    hmacs = new_hmacs[::-1]
    return NHopMixMessage(client_public_key, hmacs, address_cipher,
                          message_cipher)