def __init__(self, polynomial_list, chosen_candidate, G, com_pk):
        self.group = G
        self.com_pk = com_pk
        self.order = com_pk.order

        time_start_proof = time.process_time()
        chosen_candidate = Bn.from_num(chosen_candidate)
        random_to_eval = self.order.random()
        self.commitment_to_eval = com_pk.commit([chosen_candidate],
                                                random_to_eval)[0]

        value_eval = Bn.from_num(0)
        random_eval = Bn.from_num(0)
        commitment_eval = self.com_pk.commit([value_eval], random_eval)[0]

        self.proof = PolynomialProof(
            com_pk,
            polynomial_list,
            self.commitment_to_eval,
            commitment_eval,
            chosen_candidate,
            value_eval,
            random_to_eval,
            random_eval,
        )

        time_end_proof = time.process_time()

        self.time_proof = time_end_proof - time_start_proof
    def verify(self, polynomial_list):

        value_eval = Bn.from_num(0)
        random_eval = Bn.from_num(0)
        commitment_eval = self.com_pk.commit([value_eval], random_eval)[0]

        time_start_verify = time.process_time()
        self.proof.verify(self.com_pk, polynomial_list,
                          self.commitment_to_eval, commitment_eval)
        time_end_verify = time.process_time()

        self.time_verify = time_end_verify - time_start_verify
    def __init__(
        self,
        kp_tally,
        pk_vote,
        added_token,
        reencrypted_vote,
        randomizer,
        number_dummies,
    ):
        # Security parameters
        self.sec_param = 256
        self.bn_two = Bn.from_num(2)
        self.hash_reduction = self.bn_two.pow(self.sec_param)

        self.pk_tally = kp_tally.pk
        self.sk_tally = kp_tally.sk
        self.group_tally = self.pk_tally.group
        self.generator_tally = self.group_tally.generator()
        self.order_tally = self.group_tally.order()

        self.pk_vote = pk_vote
        self.group_vote = self.pk_vote.group
        self.generator_vote = self.pk_vote.generator
        self.order_vote = self.group_vote.order()

        self.token = added_token
        self.reencrypted_vote = reencrypted_vote
        self.nr_candidates = self.reencrypted_vote.length
        self.randomizer = randomizer
        self.number_dummies = number_dummies

        self.hiding_sk = None
        self.hiding_randomizer = None
    def __init__(self, kp_tally, pk_vote, token, vote, reencrypted_vote,
                 randomizer):
        # Security parameters
        self.sec_param = 256
        self.bn_two = Bn.from_num(2)
        self.hash_reduction = self.bn_two.pow(self.sec_param)

        # Public key used for tokens
        self.pk_tally = kp_tally.pk
        self.sk_tally = kp_tally.sk
        self.group_tally = self.pk_tally.group
        self.generator_tally = self.group_tally.generator()
        self.order_tally = self.group_tally.order()

        # Public key used for votes
        self.pk_vote = pk_vote
        self.group_vote = self.pk_vote.group
        self.generator_vote = self.group_vote.generator()
        self.order_vote = self.group_vote.order()

        self.token = token
        self.vote = vote
        self.nr_candidates = self.vote.length
        self.reencrypted_vote = reencrypted_vote
        self.randomizer = randomizer

        self.hiding_sk = None
        self.hiding_randomizer = None
    def __init__(self, com_pk, commitment, product, A, randomizers):
        self.order = com_pk.group.order()
        self.m = len(A)
        self.n = len(A[0])

        # Maybe here we have a calculation which slows down the running time
        product_rows_A = [
            modular_prod([Bn.from_num(a[i]) for a in A], self.order)
            for i in range(self.n)
        ]
        self.commitment_products, randomizer_commitment_products = com_pk.commit(
            product_rows_A)

        self.hadamard = HadamardProductArgument(
            com_pk,
            commitment,
            self.commitment_products,
            A,
            randomizers,
            randomizer_commitment_products,
        )

        self.single_value = SingleValueProdArg(
            com_pk,
            self.commitment_products,
            product,
            product_rows_A,
            randomizer_commitment_products,
        )
Beispiel #6
0
def _challenge(elements):
    """Packages a challenge in a bijective way"""
    elem = [len(elements)] + elements
    elem_str = list(map(str, elem))
    elem_len = list(map(lambda x: "%s||%s" % (len(x), x), elem_str))
    state = "|".join(elem_len)
    H = sha256()
    H.update(state.encode("utf8"))
    return Bn.from_binary(H.digest())
Beispiel #7
0
def compute_challenge_poly(transcript, p):
    """
    Compute challenge given transcript
    """
    transcript = flatten(transcript)
    m = hashlib.sha512()
    for element in transcript:
        try:
            m.update(element.commitment.export())
        except AttributeError:
            try:
                m.update(hex(element.commitment).encode())
            except:
                m.update(element.commitment.hex().encode())

    hashed = m.hexdigest()

    return (Bn.from_hex(hashed)).mod(Bn.from_num(p))
Beispiel #8
0
def election_setup(group, number_voters, security_param):
    order = group.order()
    counter_space = Bn.from_num(2).pow(security_param - 2)
    vids = []
    counter = []
    for i in range(number_voters):
        vids.append(order.random())
        index = counter_space + counter_space.random()
        counter.append(index)

    return vids, counter
Beispiel #9
0
def compute_challenge(transcript, p):
    """Compute challenge given transcript

    TODO: return something of the right size, l_c bits in the paper.
    TODO: use proper unique encoding of elements
    """

    m = hashlib.sha512()
    for element in transcript:
        try:
            m.update(element.export())
        except AttributeError:
            try:
                m.update(hex(element).encode())
            except:
                m.update(hex(element.vid).encode())
                m.update(hex(element.index).encode())
                m.update(hex(element.tag).encode())
                m.update(hex(element.vote).encode())
    hashed = m.hexdigest()

    return (Bn.from_hex(hashed)).mod(Bn.from_num(p))
    def __init__(self, commitments, responses, challenge=None):
        # Security parameters
        self.sec_param = 256
        self.bn_two = Bn.from_num(2)
        self.hash_reduction = self.bn_two.pow(self.sec_param)

        (
            self.commitment_pk,
            self.commitment_token,
            self.commitment_vote1,
            self.commitment_vote2,
        ) = commitments
        self.response_sk, self.response_randomizer = responses
        self.challenge = challenge
Beispiel #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()

    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)
    values_sum = values[0]
    if len(values) > 1:
        for i in values[1:]:
            values_sum = (values_sum + i).mod(modulo)
    return values_sum


if __name__ == "__main__":
    # import doctest
    #
    # doctest.testmod()
    G = EcGroup()
    com_pk = com.PublicKey(G, 3)
    order = com_pk.group.order()
    A = [
        [Bn.from_num(10), Bn.from_num(20),
         Bn.from_num(30)],
        [Bn.from_num(40), Bn.from_num(20),
         Bn.from_num(30)],
        [Bn.from_num(60), Bn.from_num(20),
         Bn.from_num(40)],
    ]
    for _ in range(10):
        A.extend(A)
        length_A = len(A)
        commits_rands_A = [com_pk.commit(a) for a in A]
        comm_A = [a[0] for a in commits_rands_A]
        random_comm_A = [a[1] for a in commits_rands_A]
        b = modular_prod(
            [
                modular_prod([Bn.from_num(A[i][j])
Beispiel #13
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
Beispiel #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()

    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])
Beispiel #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_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)
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)
Beispiel #17
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)
    def __init__(
            self,
            com_pk,
            A,
            B,
            random_comm_A,
            random_comm_B,
            bilinear_const=Bn.from_decimal("1"),
    ):
        """
        :param com_pk: Commitment key
        :param commitment_A: Commitment of A
        :param commitment_B: Commitment of B
        :param A: Matrix formed by rows a_i
        :param B: Matrix formed by rows b_i
        :param random_comm_A vector of random values used for commitment_A
        :param random_comm_B: vector of random values used for commitment_B
        """
        self.order = com_pk.group.order()
        self.m = len(A)
        self.n = len(A[0])
        self.bilinear_const = bilinear_const

        # Prepare announcement
        A.insert(0, [self.order.random() for _ in range(self.n)])
        B.append([self.order.random() for _ in range(self.n)])
        random_comm_A.insert(0, self.order.random())
        random_comm_B.append(self.order.random())

        self.announcement_a0, _ = com_pk.commit_reduced(
            A[0], self.n, random_comm_A[0])
        self.announcement_bm, _ = com_pk.commit_reduced(
            B[-1], self.n, random_comm_B[-1])

        diagonals = []
        for k in range(2 * self.m + 1):
            diagonal = 0
            for i in range(self.m + 1):
                j = self.m - k + i
                if j < 0:
                    continue
                if j > self.m:
                    break
                diagonal += (self.bilinear_map(A[i], B[j], self.bilinear_const,
                                               self.order)).mod(self.order)
            diagonals.append(diagonal)

        commitment_rand_diagonals = [
            self.order.random() for _ in range(2 * self.m + 1)
        ]
        commitment_rand_diagonals[self.m + 1] = 0

        self.announcement_diagonals = [
            com_pk.commit_reduced([diagonals[i]], 1,
                                  commitment_rand_diagonals[i])[0]
            for i in range(self.m * 2 + 1)
        ]
        # Prepare challenge (for the moment we only put two announcements, as I yet need to determine how to deal with
        # the matrices. Maybe I form a class, maybe not. Once decided, I'll add them here (same for announcement of
        # diagonals).
        self.challenge = compute_challenge(
            [self.announcement_a0, self.announcement_bm], self.order)
        # Compute the response
        A_modified = [[
            (A[j][i] * (self.challenge.mod_pow(j, self.order))).mod(self.order)
            for i in range(self.n)
        ] for j in range(self.m + 1)]
        self.response_as = [
            modular_sum(x, self.order) for x in zip(*A_modified[:self.m + 1])
        ]

        self.response_randomizer_A = modular_sum(
            [(self.challenge.mod_pow(i, self.order) * random_comm_A[i]).mod(
                self.order) for i in range(self.m + 1)],
            self.order,
        )

        B_modified = [[
            B[j][i] * (self.challenge.mod_pow(self.m - j, self.order))
            for i in range(self.n)
        ] for j in range(self.m + 1)]
        self.response_bs = [
            modular_sum(x, self.order) for x in zip(*B_modified[:self.m + 1])
        ]
        self.response_randomizer_B = modular_sum(
            [(self.challenge.mod_pow(self.m - i, self.order) *
              random_comm_B[i]).mod(self.order) for i in range(self.m + 1)],
            self.order,
        )

        self.response_randomizer_diagonals = modular_sum(
            [(self.challenge.mod_pow(i, self.order) *
              commitment_rand_diagonals[i]).mod(self.order)
             for i in range(self.m * 2 + 1)],
            self.order,
        )
Beispiel #19
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)
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)
    def __init__(self, com_pk, commitment, product, committed_values,
                 randomizer):
        self.n = len(committed_values)
        self.order = com_pk.group.order()

        self.sec_param_l_e = 160
        self.sec_param_l_s = 80
        self.bn_two = Bn.from_num(2)

        # Prepare announcement
        products = [committed_values[0]]
        for i in range(1, self.n):
            products.append(
                (products[i - 1] * committed_values[i]).mod(self.order))

        commitment_rand_one = self.order.random()
        commitment_rand_two = self.order.random()
        commitment_rand_three = self.order.random()

        d_randoms = [self.order.random() for _ in range(self.n)]

        delta_randoms = [self.order.random() for _ in range(self.n)]
        delta_randoms[0] = d_randoms[0]
        delta_randoms[-1] = 0

        value_to_commit_two = [
            -delta_randoms[i] * d_randoms[i + 1] for i in range(self.n - 1)
        ]
        value_to_commit_three = [
            delta_randoms[i + 1] - committed_values[i + 1] * delta_randoms[i] -
            products[i] * d_randoms[i + 1] for i in range(self.n - 1)
        ]

        self.announcement_one, _ = com_pk.commit(d_randoms,
                                                 commitment_rand_one)
        self.announcement_two, _ = com_pk.commit_reduced(
            value_to_commit_two, self.n - 1, commitment_rand_two)
        self.announcement_three, _ = com_pk.commit_reduced(
            value_to_commit_three, self.n - 1, commitment_rand_three)

        # Compute challenge [Verify validity of this]
        self.challenge = compute_challenge(
            [
                commitment,
                product,
                self.announcement_one,
                self.announcement_two,
                self.announcement_three,
            ],
            self.order,
        )

        # Compute response
        self.response_committed_values = [
            (self.challenge * committed_values[i] + d_randoms[i]).mod(
                self.order) for i in range(self.n)
        ]
        self.response_product = [
            (self.challenge * products[i] + delta_randoms[i]).mod(self.order)
            for i in range(self.n)
        ]

        self.response_randomizer = (self.challenge * randomizer +
                                    commitment_rand_one).mod(self.order)
        self.response_randomizer_commitments = (
            self.challenge * commitment_rand_three + commitment_rand_two).mod(
                self.order)
Beispiel #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()
    # 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)
Beispiel #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)

    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)
Beispiel #24
0
            product *= i
    return product


if __name__ == "__main__":
    # import doctest
    #
    # doctest.testmod()
    G = EcGroup()
    com_pk = com.PublicKey(G, 3)
    key_pair = elgamal.KeyPair(G)
    pk = key_pair.pk
    ctxts = [pk.encrypt((i) * G.generator()) for i in range(9)]
    ctxts = [ctxts[i * 3:(i + 1) * 3] for i in range(3)]
    exponents = [2, 0, 1, 3, 5, 8, 6, 7, 4]
    exponents_Bn = [Bn.from_num(i) for i in exponents]
    exponents = [exponents_Bn[i * 3:(i + 1) * 3] for i in range(3)]
    randomizers = [G.order().random() for _ in range(3)]

    reencryption_randomization = G.order().random()
    product_ctxts = prod([
        MultiExponantiation.ctxt_weighted_sum(ctxts[i], exponents[i])
        for i in range(3)
    ])

    exponantiated_reencrypted_product = (
        pk.encrypt(G.infinite(), reencryption_randomization) * product_ctxts)

    commitment_permutation = [
        com_pk.commit(exponents[i], randomizers[i])[0] for i in range(3)
    ]
Beispiel #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()
    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)
Beispiel #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 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)
Beispiel #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()
    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)
Beispiel #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)

    ## 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)
Beispiel #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 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)
Beispiel #30
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)
Beispiel #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()
    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)
Beispiel #32
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