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")
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
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
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)
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
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
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
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)
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
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")
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")
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")
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)
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")
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
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")
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)
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")
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
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
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")
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
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)
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)
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
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
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")
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()
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
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)
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)
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")
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) )
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
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)
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) )