Exemplo n.º 1
0
def dh_decrypt(priv, ciphertext, aliceVer = None):
    """ Decrypt a received message encrypted using your public key, 
    of which the private key is provided. Optionally verify 
    the message came from Alice using her verification key."""
    
    # ciphertext be (iv, ciphertext, tag, sender_pub, sig)
    # bob decrypting: check sig using alice's pub ver key,
    # then decrypt using shared key derived from priv (bob's private key)

    # check input parameter format
    if (not isinstance(ciphertext, tuple)) or (isinstance(ciphertext, tuple) and len(ciphertext) != 5):
        raise Exception("Expecting tuple (iv, ciphertext, tag, sender public key, signature).")
    iv, encmsg, tag, sender_pub, sig = ciphertext

    # verify signature
    if aliceVer:
        if not sig:
           raise Exception("Signature required before decyption.")
        elif not do_ecdsa_verify(EcGroup(), aliceVer, sig, sha256(encmsg).digest()):
           raise Exception("Signature verification failed.")
    
    # shared key = bob priv x alice's pub point
    shared_key = priv * sender_pub
    # hash
    shared_key = sha256(shared_key.export()).digest()

    # decrypt
    aes = Cipher("aes-256-gcm")
    plaintext = aes.quick_gcm_dec(shared_key, iv, encmsg, tag)

    return plaintext.encode("utf-8")
Exemplo n.º 2
0
def dh_encrypt(pub, message):
    """ Assume you know the public key of someone else (Bob), 
    and wish to Encrypt a message for them.
        - Generate a fresh DH key for this message.
        - Derive a fresh shared key.
        - Use the shared key to AES_GCM encrypt the message.
        - Optionally: sign the message.
    """

    Group, private, public = dh_get_key()  #generate new DH pair for Alice
    #private key is an integer/scalar and public key is a point on the curve

    #check whether public key of Bob is valid and on curve
    assert Group.check_point(pub)

    #Alice obtains shared secret by multiplying her private key with bob's forwarded public key
    key = pub.pt_mul(private)  #dA* qB
    print "key from enc is", key

    hashedKey = sha256(key.export()).digest()

    plaintext = message.encode("utf8")  #encode message
    aes = Cipher("aes-128-gcm")  #select cipher
    iv = urandom(16)  #generate initialization vector
    cipher, tag = aes.quick_gcm_enc(hashedKey[:16], iv,
                                    plaintext)  #encrypt using shared key
    ciphertext = [iv, cipher, tag, public]

    return ciphertext
def dh_encrypt(pub, message):
    """ Assume you know the public key of someone else (Bob), 
    and wish to Encrypt a message for them.
        - Generate a fresh DH key for this message.
        - Derive a fresh shared key.
        - Use the shared key to AES_GCM encrypt the message.
        - Optionally: sign the message.
    """
    
    Group, private, public = dh_get_key()#generate new DH pair for Alice
    #private key is an integer/scalar and public key is a point on the curve 
    
    #check whether public key of Bob is valid and on curve 
    assert Group.check_point(pub)
    
    #Alice obtains shared secret by multiplying her private key with bob's forwarded public key
    key = pub.pt_mul(private)#dA* qB
    print "key from enc is", key
    
    hashedKey=sha256(key.export()).digest()

    
    plaintext = message.encode("utf8")#encode message
    aes = Cipher("aes-128-gcm")#select cipher
    iv = urandom(16)#generate initialization vector 
    cipher, tag = aes.quick_gcm_enc(hashedKey[:16], iv, plaintext)#encrypt using shared key  
    ciphertext = [iv,cipher,tag,public]

    return ciphertext
Exemplo n.º 4
0
 def aes_enc_dec(self, key, iv, input_):
     """A helper function which implements the AES-128 encryption in counter mode CTR"""
     aes = Cipher("AES-128-CTR")
     enc = aes.enc(key, iv)
     output = enc.update(input_)
     output += enc.finalize()
     return output
Exemplo n.º 5
0
def dh_encrypt(pub, message, aliceSig = None):
    """ Assume you know the public key of someone else (Bob), 
    and wish to Encrypt a message for them.
        - Generate a fresh DH key for this message.
        - Derive a fresh shared key.
        - Use the shared key to AES_GCM encrypt the message.
        - Optionally: sign the message with Alice's key.
    """
    
    # pub is bob's pub key, alicesig is my private sig key,
    # which shuold be different from enc/dec keypair
    # for cryptographic sec reasons

    # priv is an integer, pub is an ec point
    alice_G, alice_priv, alice_pub = dh_get_key()

    # shared secret = my priv x bob's pub point
    shared_key = alice_priv * pub
    # hash ec pt to derive key
    shared_key = sha256(shared_key.export()).digest()

    # aes_gcm encrypt
    aes = Cipher("aes-256-gcm")
    iv = urandom(len(shared_key))
    ciphertext, tag = aes.quick_gcm_enc(shared_key, iv, message.encode("utf-8"))

    # sign message (assume using common curve)
    # hash ciphertext
    sig = do_ecdsa_sign(EcGroup(), aliceSig, sha256(ciphertext).digest()) if aliceSig else None

    # return alice_pub for dh_decrypt on bob side
    # (because bob needs alice's pub to gen shared secret)
    return (iv, ciphertext, tag, alice_pub, sig)
Exemplo n.º 6
0
 def aes_enc_dec(self, data):
  ''' AES Enc/Dec '''
  aes = Cipher("AES-128-CBC")
  enc = aes.enc(self.key, self.ctr_iv)
  output = enc.update(data)
  output += enc.finalize()
  return output
Exemplo n.º 7
0
def dh_encrypt(pub, message, aliceSig=None):
    """ Assume you know the public key of someone else (Bob), 
    and wish to Encrypt a message for them.
        - Generate a fresh DH key for this message.
        - Derive a fresh shared key.
        - Use the shared key to AES_GCM encrypt the message.
        - Optionally: sign the message with Alice's key.
    """

    ## YOUR CODE HERE
    # Bob's public key is a point on the curve
    bob_pub = pub

    G, alice_priv, alice_pub = dh_get_key()
    # Alice's private key is a scalar
    # shared_key_point = bob_pub * alice_priv # this is multiplication of a point with a scalar
    shared_key_point = bob_pub.pt_mul(alice_priv)
    # We convert this shared_key point to a
    # string binary representation with .export
    #
    # .export :
    # "Returns a string binary representation
    #  of the point in compressed coordinates"
    shared_key_point_binary = shared_key_point.export()
    # Then we hash the value to produce a 256 bit key
    shared_key = sha256(shared_key_point_binary).digest()
    plaintext = message.encode("utf8")

    ## YOUR CODE HERE
    aes = Cipher("aes-256-gcm")
    iv = urandom(16)
    encrypted_text, tag = aes.quick_gcm_enc(shared_key, iv, plaintext)
    # iv, encrypted_text, tag = encrypt_message(shared_key, message)
    return alice_pub, iv, encrypted_text, tag
Exemplo n.º 8
0
 def aes_cbc(self, key, IV, data):
     #Input: Encryption key, Initialization vector, data to encrypt
     #Output: Encrypted data with IV and key
     aes = Cipher("AES-128-CBC")
     enc = aes.enc(key, IV)
     output = enc.update(data)
     output += enc.finalize()
     return output
Exemplo n.º 9
0
def encrypt_message(K, message):
    """ Encrypt a message under a key K """

    plaintext = message.encode("utf8")
    aes = Cipher("aes-128-gcm")
    iv = urandom(16)
    ciphertext, tag = aes.quick_gcm_enc(K, iv, plaintext)
    return (iv, ciphertext, tag)
Exemplo n.º 10
0
def encrypt_message(K, message, key_length=16):
    """ Encrypt a message under a key K """

    plaintext = message.encode("utf8")
    aes = Cipher("aes-{}-gcm".format(key_length * 8))
    iv = urandom(key_length)
    ciphertext, tag = aes.quick_gcm_enc(K, iv, plaintext)

    return iv, ciphertext, tag
Exemplo n.º 11
0
def decrypt_message(K, iv, ciphertext, tag, key_length=16):
    """ Decrypt a cipher text under a key K 

        In case the decryption fails, throw an exception.
    """
    aes = Cipher("aes-{}-gcm".format(key_length * 8))
    plain = aes.quick_gcm_dec(K, iv, ciphertext, tag)

    return plain.encode("utf8")
Exemplo n.º 12
0
def decrypt_message(K, iv, ciphertext, tag):
    """ Decrypt a cipher text under a key K 

        In case the decryption fails, throw an exception.
    """
    aes = Cipher("aes-128-gcm")
    plain = aes.quick_gcm_dec(K, iv, ciphertext, tag)

    return plain.encode("utf8")
Exemplo n.º 13
0
def decrypt_message(K, iv, ciphertext, tag):
    """ Decrypt a cipher text under a key K 

        In case the decryption fails, throw an exception.
    """
    ## YOUR CODE HERE
    aes = Cipher("aes-128-gcm")  # Initialize AES-GCM with 128 bit keys
    plain = aes.quick_gcm_dec(K, iv, ciphertext, tag)

    return plain.encode("utf8")
Exemplo n.º 14
0
def decrypt_message(K, iv, ciphertext, tag):
    """ Decrypt a cipher text under a key K 

        In case the decryption fails, throw an exception.
    """
    aes = Cipher("aes-128-gcm")
    plain = aes.quick_gcm_dec(K, iv, ciphertext, tag)
    
    
    return plain.encode("utf8")
Exemplo n.º 15
0
def encrypt_message(K, message):
    """ Encrypt a message under a key K """
    ## YOUR CODE HERE
    plaintext = message.encode("utf8")

    aes = Cipher("aes-128-gcm")  # Initialize AES-GCM with 128 bit keys
    iv = urandom(16)
    # Encryption using AES-GCM returns a ciphertext and a tag
    ciphertext, tag = aes.quick_gcm_enc(K, iv, plaintext)

    return (iv, ciphertext, tag)
Exemplo n.º 16
0
def dh_decrypt(priv, ciphertext, aliceVer=None):
    """ Decrypt a received message encrypted using your public key, 
    of which the private key is provided. Optionally verify 
    the message came from Alice using her verification key."""

    ## YOUR CODE HERE
    iv, ciphertext, tag, pub_enc = ciphertext
    freshKey = pub_enc.pt_mul(priv).export()[:16]
    aes = Cipher("aes-128-gcm")
    plaintext = aes.quick_gcm_dec(freshKey, iv, ciphertext, tag)
    return plaintext.encode("utf8")
Exemplo n.º 17
0
def dh_decrypt(priv, ciphertext, aliceVer=None):
    """ Decrypt a received message encrypted using your public key, 
    of which the private key is provided. Optionally verify 
    the message came from Alice using her verification key."""
    iv, enc_msg, tag, pub_enc = ciphertext
    shared_key = pub_enc.pt_mul(priv).export()
    hashed_shared_key = sha256(shared_key).digest()
    aes = Cipher("aes-128-gcm")
    plaintext = aes.quick_gcm_dec(hashed_shared_key[:16], iv, enc_msg,
                                  tag).encode("utf-8")
    return plaintext
Exemplo n.º 18
0
def decrypt_message(K, iv, ciphertext, tag):
    """ Decrypt a cipher text under a key K 
        In case the decryption fails, throw an exception.
    """
    ## YOUR CODE HERE
    try:
        aes = Cipher("aes-128-gcm")
        plain = aes.quick_gcm_dec(K, iv, ciphertext, tag)
    except:
        raise Exception("decryption failed")

    return plain.encode("utf8")
Exemplo n.º 19
0
def encrypt_message(K, message):
    """ Encrypt a message under a key K """

    plaintext = message.encode("utf8")
    
    aes = Cipher("aes-128-gcm")
    iv = urandom(16)
    # Encryption using AES-GCM returns a ciphertext and a tag
    ciphertext, tag = aes.quick_gcm_enc(K, iv, plaintext) 
    

    return (iv, ciphertext, tag)
Exemplo n.º 20
0
def decrypt_message(K, iv, ciphertext, tag):
    """ Decrypt a cipher text under a key K 

        In case the decryption fails, throw an exception.
    """
    ## YOUR CODE HERE

    # we declare the aes cipher
    aes = Cipher("aes-128-gcm")
    # we decode the ciphertext
    plain = aes.quick_gcm_dec(K, iv, ciphertext, tag)
    # we return the unencrypted message
    return plain.encode("utf8")
Exemplo n.º 21
0
def aes_ctr_enc_dec(key, iv, input):
    """ A helper function that implements AES Counter (CTR) Mode encryption and decryption. 
    Expects a key (16 byte), and IV (16 bytes) and an input plaintext / ciphertext.

    If it is not obvious convince yourself that CTR encryption and decryption are in 
    fact the same operations.
    """
    
    aes = Cipher("AES-128-CTR")
    enc = aes.enc(key, iv)
    output = enc.update(input)
    output += enc.finalize()

    return output
Exemplo n.º 22
0
def aes_ctr_enc_dec(key, iv, input):
    """ A helper function that implements AES Counter (CTR) Mode encryption and decryption. 
    Expects a key (16 byte), and IV (16 bytes) and an input plaintext / ciphertext.
    If it is not obvious convince yourself that CTR encryption and decryption are in 
    fact the same operations.
    """

    aes = Cipher("AES-128-CTR")

    enc = aes.enc(key, iv)
    output = enc.update(input)
    output += enc.finalize()

    return output
Exemplo n.º 23
0
def decrypt_message(K, iv, ciphertext, tag):
    """ Decrypt a cipher text under a key K 

        In case the decryption fails, throw an exception.
    """
    plain = ''
    aes = Cipher("aes-128-gcm")
    try:    
        plain = aes.quick_gcm_dec(K, iv, ciphertext,tag)
        plain = plain.decode("utf8")
    except:
        raise Exception('decryption failed')

    return plain
Exemplo n.º 24
0
def decrypt_message(K, iv, ciphertext, tag, key_length=128):
    """ Decrypt a cipher text under a key K 

        In case the decryption fails, throw an exception.
    """

    if key_length not in [128, 192, 256]:
        raise Exception("Invalid key length")

    aes = Cipher("aes-%s-gcm" % str(key_length))

    plain = aes.quick_gcm_dec(K, iv, ciphertext, tag)

    return plain.encode("utf8")
Exemplo n.º 25
0
def decrypt_message(K, iv, ciphertext, tag):
    """ Decrypt a cipher text under a key K

        In case the decryption fails, throw an exception.
    """
    ## YOUR CODE HERE tests
    aes = Cipher("aes-128-gcm")
    try:
        m = aes.quick_gcm_dec(K, iv, ciphertext,tag)
        m = m.decode("utf8")
    except:
        raise Exception('decryption failed')

    return m
Exemplo n.º 26
0
def encrypt_message(K, message):
    """ Encrypt a message under a key K """

    plaintext = message.encode("utf8")

    ## YOUR CODE HERE

    # we declare the aes cipher
    aes = Cipher("aes-128-gcm")
    # we generate the iv
    iv = urandom(16)
    # we encrypt the message "plaintext" using the key K provided and the iv we generated
    ciphertext, tag = aes.quick_gcm_enc(K, iv, plaintext)

    return (iv, ciphertext, tag)
Exemplo n.º 27
0
def encrypt_message(K, message, key_length=128):
    """ Encrypt a message under a key K """

    plaintext = message.encode("utf8")

    iv = urandom(16)

    if key_length not in [128, 192, 256]:
        raise Exception("Invalid key length")

    aes = Cipher("aes-%s-gcm" % str(key_length))

    ciphertext, tag = aes.quick_gcm_enc(K, iv, plaintext)

    return (iv, ciphertext, tag)
Exemplo n.º 28
0
def test_cbc_enc_dec():

    aes = Cipher("AES-128-CBC")
    key = urandom(16)
    iv = urandom(16)
    ipt = "Hello"

    enc = aes.enc(key, iv)
    ciphertext = enc.update(ipt)
    ciphertext += enc.finalize()

    dec = aes.dec(key, iv)
    plaintext = dec.update(ciphertext)
    plaintext += dec.finalize()

    assert ipt == plaintext
Exemplo n.º 29
0
    def cascade_rebuild(self, seed, key, iv, flags, inverse, data):
        #Cascade Rebuild data processing function
        #print "MIX: Cascade Rebuild enc/perm"
        if not inverse and not flags[2]:
            data = self.permute(seed, data, inverse)

        aes = Cipher("AES-128-CTR")
        enc = aes.enc(key, iv)

        #for i in range(len(data)):
        #	data[i] = enc.update(data[i])
        #	data[i] += enc.finalize()

        if inverse and not flags[2]:
            data = self.permute(seed, data, inverse)
        return data
Exemplo n.º 30
0
    def __init__(self, G, name, priv, pki):
        # Maths
        self.G = G
        self.g = self.G.generator()
        self.order = self.G.order()

        ## Store keys
        self.priv = priv
        self.pub = priv * self.g

        self.pki = pki
        self.name = name

        # Which channel are we in?
        self.admins = []
        self.members = []

        # Channel key stores
        self.Ks = []

        ## Generate an ephemeral signature key
        self.priv_sign = self.order.random()
        self.pub_sign = self.priv_sign * self.g

        ## Storage for short term dictionaries
        self.current_dict = {"me": self.pub_sign}

        ## Generate an ephemeral signature key
        self.priv_enc = self.order.random()
        self.pub_enc = self.priv_enc * self.g

        self.aes = Cipher("aes-128-gcm")
Exemplo n.º 31
0
    def __init__(self, group=None, header_len = 192, body_len = 1024, assoc_len=0, k=16, dest_len=16):
        self.aes = Cipher("AES-128-CTR")
        self.cbc = Cipher("AES-128-CBC")

        self.assoc_len = assoc_len
        self.max_len = header_len

        self.zero_pad = b"\x00" * (2 * self.max_len)

        self.m = body_len
        self.k = k
        self.dest_len = dest_len

        self.group = group
        if not group:
            self.group = Group_ECC()
Exemplo n.º 32
0
 def decrypt_aes_gcm(self, msg, secret):
     aes = Cipher.aes_128_gcm()
     g_x, iv, ciphertext, tag = msg
     d_key = self.G.expon(g_x, secret).export()
     d_key = sha256(d_key).digest()[:16]
     msg = aes.quick_gcm_dec(d_key, iv, ciphertext, tag)
     return msg
Exemplo n.º 33
0
class PublicParams(object):
    ec_group = attrib(default=Factory(EcGroup))
    hash_func = attrib(default=Factory(lambda: sha256))
    enc_cipher = attrib(default=Factory(lambda: Cipher("aes-128-gcm")))
    enc_key_size = attrib(default=16)
    lookup_key_size = attrib(default=8)
    nonce_size = attrib(default=16)
Exemplo n.º 34
0
def dh_encrypt(pub, message, aliceSig=None):
    """ Assume you know the public key of someone else (Bob), 
    and wish to Encrypt a message for them.
        - Generate a fresh DH key for this message.
        - Derive a fresh shared key.
        - Use the shared key to AES_GCM encrypt the message.
        - Optionally: sign the message with Alice's key.
    """
    (G, priv_dec, pub_enc) = dh_get_key()
    shared_key = pub.pt_mul(priv_dec).export()
    hashed_shared_key = sha256(shared_key).digest()
    iv = urandom(16)
    aes = Cipher("aes-128-gcm")
    ciphertext, tag = aes.quick_gcm_enc(hashed_shared_key[:16], iv,
                                        message.encode("utf-8"))
    return (iv, ciphertext, tag, pub_enc)
Exemplo n.º 35
0
def dh_decrypt(priv, ciphertext):
    """ Decrypt a received message encrypted using your public key, 
    of which the private key is provided"""
    Group1,private, public = dh_get_key()#generate new DH pair for Bob
    iv=ciphertext[0]
    cipher=ciphertext[1]
    tag=ciphertext[2]
    pubA=ciphertext[3]
    
    #Bob derives shared secret key by multiplying his public key with Alice's private key
    shared2 = pubA.pt_mul(priv)#qA * dB
    print "key from dec is", shared2

    hashedKey=sha256(shared2.export()).digest()
    
    aes = Cipher("aes-128-gcm")
    plain = aes.quick_gcm_dec(hashedKey[:16], iv, cipher, tag)#where to get IV and tag from ???
    
    return plain.encode("utf8")
Exemplo n.º 36
0
def mix_operate(message, triplet, setup):
    mname, mpub, msec = triplet
    elem, forward, backwards = message
    G, o, g, o_bytes = setup

    aes = Cipher("AES-128-CTR")

    # Derive first key
    k1 = KDF((msec * elem).export())

    # Derive the blinding factor
    b = Bn.from_binary(k1.b) % o
    new_elem = b * elem

    # Check the forward MAC
    mac1 = hmac.new(k1.kmac, forward[20:], digestmod=sha1).digest()
    assert forward[:20] == mac1

    # Decrypt the payload
    enc = aes.dec(k1.kenc, k1.iv)        
    pt = enc.update(forward[20:])
    pt += enc.finalize()

    # Parse the forward message
    xfrom, xto, the_bs, new_forw = pt[:4], pt[4:8], pt[8:8+o_bytes], pt[8+o_bytes:]
    old_bs = Bn.from_binary(the_bs)

    # Now encrypt the return part
    k2 = KDF(((msec * old_bs) * elem).export())


    new_bs = old_bs.mod_inverse(o).binary()
        
    enc = aes.enc(k2.kenc, k2.iv)
    new_back_body = enc.update(xto + xfrom + new_bs + backwards)
    new_back_body += enc.finalize()
    mac2 = hmac.new(k2.kmac, new_back_body, digestmod=sha1).digest()

    new_back = mac2 + new_back_body

    return ((xfrom, xto), (new_elem, new_forw, new_back) )
Exemplo n.º 37
0
def test_fails():
    G1, private1, public1 = dh_get_key()
    msg = u"Test" * 1000
    ciphertext=dh_encrypt(public1,msg)
    iv=ciphertext[0]#get IV from dh_encrypt()
    tag=ciphertext[2]#tag
    pubA=ciphertext[3]#Alice's public key
    
    #derive shared secret by doing qA * dB 
    shared=pubA.pt_mul(private1)
    hashedKey=sha256(shared.export()).digest()
    print "shared in fail is", shared
    
    mess=msg.encode("utf8")
    aes = Cipher.aes_128_gcm()          # Initialize AES cipher
    enc = aes.enc(hashedKey[:16], iv)           # Get an encryption CipherOperation
    ciphertext2 = enc.update(mess)  # Include some plaintext
    nothing = enc.finalize()            # Finalize
    tag2 = enc.get_tag(16)               # Get the AES-GCM tag
    
    if tag==tag2:#only attempt to decrypt if tag is valid !
        assert dh_decrypt(private1,ciphertext)==mess
    else: 
        assert False 
Exemplo n.º 38
0
def mix_package(sender, receiver, triplets):
    ''' Package a message through a mix-net. '''

    aes = Cipher("AES-128-CTR")

    Bs = []

    _, ypub, y = sender
    pubs = [ ypub ]

    round_trip = triplets + [ receiver ] + list(reversed(triplets))

    secrets = []
    prod_bs = Bn(1)
    for i, (mname, mpub, msec) in enumerate(round_trip):
        xysec2 = (y * prod_bs) * mpub
        secrets += [ xysec2 ]

        if __debug__ and msec is not None:
            xysec1 = (msec *  prod_bs) * ypub
            assert xysec2  == xysec1

        # Blinding factor
        k = KDF(xysec2.export())
        b = Bn.from_binary(k.b) % o
        Bs += [ b ]
        # y = (b * y) % o
        prod_bs = (b * prod_bs) % o
        #ypub = b * ypub
        pubs += [ prod_bs * ypub ]

    # Precompute the correction factors
    correction_factors = []
    for i in range(len(triplets)):
        
        total_b = Bn(1)
        for j in range(i, 2 * len(triplets) - i):
            total_b = (total_b * Bs[j]) % o

        assert round_trip[i][0] ==  round_trip[2 * len(triplets) - i][0]
        assert total_b * pubs[i] == pubs[2 * len(triplets) - i]

        correction_factors += [ total_b ]

    all_factors = [] + correction_factors
    all_factors += [ Bn(1) ]
    all_factors += [bf.mod_inverse(o) for bf in reversed(correction_factors)]
    assert len(all_factors) == len(round_trip)

    # Generate data stream
    data = [ sender ] + round_trip + [ sender ]
    addressing = []
    for i, _ in enumerate(round_trip):
        addressing += [(data[1 + i-1][0], data[1 + i+1][0])]

    # Derive all keys
    all_data = zip(round_trip, all_factors, pubs, addressing, secrets) 
    all_keys = []
    for (mname, mpub, msec), bs, yelem, (xfrom, xto), Ksec in all_data:
        
        k1 = KDF(Ksec.export())
        k2 = KDF( (bs * Ksec).export())

        all_keys += [(k1, k2)]
        
    all_data = zip(round_trip, all_factors, pubs, addressing, all_keys) 

    # Build the backwards path
    prev = ''
    backwards_stages = [ ]
    for j in range(len(mix_names) + 1):
        (mname, mpub, msec), bs, yelem, (xfrom, xto), (k1, k2) = all_data[j]
        the_bs = bs.mod_inverse(o).binary()
        
        enc = aes.enc(k2.kenc, k2.iv)
        ciphertext = enc.update(xto + xfrom + the_bs + prev)
        ciphertext += enc.finalize()

        mac = hmac.new(k2.kmac, ciphertext, digestmod=sha1).digest()

        prev = mac + ciphertext
        backwards_stages += [ prev ]

    # Build the forwards path
    prev = ''
    forwards_stages = []
    for jp in range(len(mix_names) + 1):
        j = len(mix_names) - jp

        (mname, mpub, msec), bs, yelem, (xfrom, xto), (k1, k2) = all_data[j]
        the_bs = bs.binary()
        
        enc = aes.enc(k1.kenc, k1.iv)
        ciphertext = enc.update(xfrom + xto + the_bs + prev)
        ciphertext += enc.finalize()

        mac = hmac.new(k1.kmac, ciphertext, digestmod=sha1).digest()

        prev = mac + ciphertext
        forwards_stages += [ prev ]

    forwards_stages = list(reversed(forwards_stages))

    stages = zip(forwards_stages, backwards_stages)

    # Check all the MACs
    if __debug__:
        for j in range(len(mix_names) + 1):
            (msg_f, msg_b) = stages.pop(0)

            (mname, mpub, msec), bs, yelem, (xfrom, xto), (k1, k2) = all_data[j]
            
            mac1 = hmac.new(k1.kmac, msg_f[20:], digestmod=sha1).digest()
            assert msg_f[:20] == mac1

            enc = aes.dec(k1.kenc, k1.iv)        
            plaintext = enc.update(msg_f[20:])
            plaintext += enc.finalize()

            assert xfrom == plaintext[:4] and xto == plaintext[4:8]

            mac2 = hmac.new(k2.kmac, msg_b[20:], digestmod=sha1).digest()
            assert msg_b[:20] == mac2
    # End __debug__

    return zip(pubs[:len(mix_names) + 1], forwards_stages + [''], [''] + backwards_stages)
Exemplo n.º 39
0
def mix_operate(message, triplet, setup, generate_return_message=False):
    ''' Operate a Mix with a received message, and its keys. '''


    mname, mpub, msec = triplet
    elem, forward, backwards = message
    G, o, g, o_bytes = setup

    aes = Cipher("AES-128-CTR")

    # Derive first key
    k1 = KDF((msec * elem).export())

    # Derive the blinding factor
    b = Bn.from_binary(k1.b) % o
    new_elem = b * elem

    # Check the forward MAC
    mac1 = hmac.new(k1.kmac, forward[20:], digestmod=sha1).digest()
    if not (forward[:20] == mac1):
        raise Exception("Wrong MAC1")

    # Decrypt the payload
    enc = aes.dec(k1.kenc, k1.iv)        
    pt = enc.update(forward[20:])
    pt += enc.finalize()

    # Parse the forward message
    xcode = pt[0]
    if not (xcode == "0" or xcode == "1"):
        raise Exception("Wrong routing code")

    pt = pt[1:]

    if xcode == "0":

        xfrom, xto, the_bs, new_forw = pt[:4], pt[4:8], pt[8:8+o_bytes], pt[8+o_bytes:]
        old_bs = Bn.from_binary(the_bs)

        # Now package the return part
        k2 = KDF(((msec * old_bs) * elem).export())
            
        enc = aes.enc(k2.kenc, k2.iv)
        new_back_body = enc.update("1" + xto + xfrom + backwards)
        new_back_body += enc.finalize()
        mac2 = hmac.new(k2.kmac, new_back_body, digestmod=sha1).digest()

        new_back = mac2 + new_back_body

        if generate_return_message:
            ret_elem = old_bs * elem
            ret_forw = new_back
            ret_back = None
            
            return ((xto, xfrom), (ret_elem, ret_forw, ret_back) )            

    else:

        xfrom, xto, new_forw = pt[:4], pt[4:8], pt[8:]

        # Returns do not need to build returns
        if not (backwards == None):
            raise Exception("Backwards header should be None")

        new_back = None

    return ((xfrom, xto), (new_elem, new_forw, new_back) )