示例#1
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

    return OneHopMixMessage(client_public_key, expected_mac, address_cipher,
                            message_cipher)
示例#2
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()

    #TODO ADD CODE HERE
    
    return OneHopMixMessage(client_public_key, expected_mac, address_cipher, message_cipher)
示例#3
0
class Group_ECC:
    "Group operations in ECC"

    def __init__(self, gid=713):
        self.G = EcGroup(gid)
        self.g = self.G.generator()

    def gensecret(self):
        return self.G.order().random()

    def expon(self, base, exp):
        x = exp[0]
        for f in exp[1:]:
            x = x.mod_mul(f, self.G.order())
        b = base
        return (x * b)

    def expon_base(self, exp):
        x = exp[0]
        for f in exp[1:]:
            x = x.mod_mul(f, self.G.order())
        return (x * self.g)

    def makeexp(self, data):
        return (Bn.from_binary(data) % self.G.order())

    def in_group(self, alpha):
        # All strings of length 32 are in the group, says DJB
        b = alpha
        return self.G.check_point(b)

    def printable(self, alpha):
        return alpha.export(POINT_CONVERSION_UNCOMPRESSED)
示例#4
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)
示例#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()

    ## 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)
示例#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()

    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)
示例#10
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)
示例#11
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
示例#12
0
文件: BLcred.py 项目: xoSauce/petlib
def test_protocol():
    # Parameters of the BL schemes
    G = EcGroup(713)
    q = G.order()

    g = G.hash_to_point(b"g")
    h = G.hash_to_point(b"h")
    z = G.hash_to_point(b"z")
    hs = [G.hash_to_point(("h%s" % i).encode("utf8")) for i in range(100)]

    # Inputs from user
    R = q.random()
    L1 = 10
    L2 = 20
    C = R * hs[0] + L1 * hs[1] + L2 * hs[2]
    m = b"Hello World!"

    # Inputs from the Issuer
    # TODO: check ZK on C
    x = q.random()
    y = x * g

    # Preparation
    rnd = q.random()
    z1 = C + rnd * g
    z2 = z + (-z1)

    ## Send: (rnd,) to user
    if rnd % q == 0:
        raise

    z1 = C + rnd * g
    gam = q.random()
    zet = gam * z
    zet1 = gam * z1
    zet2 = zet + (-zet1)
    tau = q.random()
    eta = tau * z

    # Validation: Issuer
    u, r1p, r2p, cp = [q.random() for _ in range(4)]
    a = u * g
    a1p = r1p * g + cp * z1
    a2p = r2p * h + cp * z2

    ## Send(a, ap = (a1p, a2p))
    # User side

    assert G.check_point(a)
    assert G.check_point(a1p)
    assert G.check_point(a2p)

    t1, t2, t3, t4, t5 = [q.random() for _ in range(5)]
    alph = a + t1 * g + t2 * y
    alph1 = gam * a1p + t3 * g + t4 * zet1
    alph2 = gam * a2p + t5 * h + t4 * zet2

    # Make epsilon
    H = [zet, zet1, alph, alph1, alph2, eta]
    Hstr = list(map(EcPt.export, H)) + [m]
    Hhex = b"|".join(map(b64encode, Hstr))
    epsilon = Bn.from_binary(sha256(Hhex).digest()) % q

    e = epsilon.mod_sub(t2, q).mod_sub(t4, q)

    ## Send: (e,) to Issuer
    c = e.mod_sub(cp, q)
    r = u.mod_sub((c * x), q)

    ## Send: (c,r, cp, rp = (r1p, r2p)) to User
    ro = r.mod_add(t1, q)
    om = c.mod_add(t2, q)
    ro1p = (gam * r1p + t3) % q
    ro2p = (gam * r2p + t5) % q
    omp = (cp + t4) % q
    mu = (tau - omp * gam) % q

    signature = (m, zet, zet1, zet2, om, omp, ro, ro1p, ro2p)

    # Check verification equation
    lhs = (om + omp) % q
    rhs_h = [
        zet,
        zet1,
        ro * g + om * y,
        ro1p * g + omp * zet1,
        ro2p * h + omp * zet2,  ## problem
        mu * z + omp * zet
    ]

    Hstr = list(map(EcPt.export, rhs_h)) + [m]
    Hhex = b"|".join(map(b64encode, Hstr))
    rhs = Bn.from_binary(sha256(Hhex).digest()) % q

    # Check the (future) ZK proof
    assert zet == gam * z
    gam_hs = [gam * hsi for hsi in hs]
    gam_g = gam * g
    assert rnd * gam_g + R * gam_hs[0] + L1 * gam_hs[1] + L2 * gam_hs[2] == zet1

    print(rhs == lhs)
示例#13
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
示例#14
0
def test_protocol():
    # Parameters of the BL schemes
    G = EcGroup(713)
    q = G.order()

    g = G.hash_to_point(b"g")
    h = G.hash_to_point(b"h")
    z = G.hash_to_point(b"z")
    hs = [G.hash_to_point(("h%s" % i).encode("utf8")) for i in range(100)]

    # Inputs from user
    R = q.random()
    L1 = 10
    L2 = 20 #age
    C = R * hs[0] + L1 * hs[1] + L2 * hs[2]
    m = b"Hello World!"

    # Inputs from the Issuer
    # TODO: check ZK on C
    x = q.random()
    y = x * g

    # Preparation
    rnd = q.random()
    z1 = C + rnd * g
    z2 = z + (-z1)

    ## Send: (rnd,) to user
    if rnd % q == 0:
        raise

    z1 = C + rnd * g
    gam = q.random()
    zet = gam * z
    zet1 = gam * z1
    zet2 = zet + (-zet1)
    tau = q.random()
    eta = tau * z

    # Validation: Issuer
    u, r1p, r2p, cp = [q.random() for _ in range(4)]
    a = u * g
    a1p = r1p * g + cp * z1
    a2p = r2p * h + cp * z2

    ## Send(a, ap = (a1p, a2p))
    # User side

    assert G.check_point(a)
    assert G.check_point(a1p)
    assert G.check_point(a2p)

    t1, t2, t3, t4, t5 = [q.random() for _ in range(5)]
    alph = a + t1 * g + t2 * y
    alph1 = gam * a1p + t3 * g + t4 * zet1
    alph2 = gam * a2p + t5 * h + t4 * zet2

    # Make epsilon
    H = [zet, zet1, alph, alph1, alph2, eta]
    Hstr = list(map(EcPt.export, H)) + [m]
    Hhex = b"|".join(map(b64encode, Hstr))
    epsilon = Bn.from_binary(sha256(Hhex).digest()) % q

    e = epsilon.mod_sub(t2, q).mod_sub(t4, q)

    ## Send: (e,) to Issuer
    c = e.mod_sub(cp, q)
    r = u.mod_sub((c * x), q)

    ## Send: (c,r, cp, rp = (r1p, r2p)) to User
    ro = r.mod_add(t1, q)
    om = c.mod_add(t2, q)
    ro1p = (gam * r1p + t3) % q
    ro2p = (gam * r2p + t5) % q
    omp = (cp + t4) % q
    mu = (tau - omp * gam) % q

    signature = (m, zet, zet1, zet2, om, omp, ro, ro1p, ro2p)

    gam_hs = [gam * hsi for hsi in hs]
    zet1p = zet1 - L2 * gam_hs[2]

    # Check verification equation
    lhs = (om + omp) % q
    rhs_h = [zet, zet1p,
             ro * g + om * y,
             ro1p * g + omp * zet1p,
             ro2p * h + omp * zet2,  ## problem
             mu * z + omp * zet]

    Hstr = list(map(EcPt.export, rhs_h)) + [m]
    Hhex = b"|".join(map(b64encode, Hstr))
    rhs = Bn.from_binary(sha256(Hhex).digest()) % q

    # Check the (future) ZK proof
    assert zet == gam * z
    gam_hs = [gam * hsi for hsi in hs]
    gam_g = gam * g
    #assert rnd * gam_g + R * gam_hs[0] + L1 * gam_hs[1] + L2 * gam_hs[2] == zet1
    assert rnd * gam_g + R * gam_hs[0] + L1 * gam_hs[1] == zet1 - L2 * gam_hs[2]

    print(rhs == lhs)
示例#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()
    # 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)