def encrypt_and_put(self, data, data_id, key_encryption, key_auth, data_iv): # Re-encrypt the data. if isinstance(data, self.node): data = data.to_json_obj() elif isinstance(data, self.merkle_node): data = data.to_json_obj() json_data = util.to_json_string(data) new_encrypt_data = self.crypto.symmetric_encrypt(json_data, key_encryption, 'AES', 'CBC', IV=data_iv) string_new_encrypt_data = util.to_json_string( [new_encrypt_data, data_iv]) sign_new_encrypt_data = self.crypto.message_authentication_code( string_new_encrypt_data, key_auth, 'SHA512') # Put new_encrypt_data back in server string_data = util.to_json_string( (new_encrypt_data, sign_new_encrypt_data, data_iv)) self.storage_server.put(data_id, string_data) # 'MERKEL TREE' self.crypto.cryptographic_hash(string_data, 'SHA256') return self.crypto.cryptographic_hash(string_data, 'SHA256')
def share(self, user, name): # Replace with your implementation (not needed for Part 1) keys = self.get_file_keys(name) ka, ke = keys file_info = self.get_owner_and_encrypted_original_filename(name) encrypted_original_filename = file_info[1] share_id = path_join(self.username, encrypted_original_filename, "shared_with") share_list_string = self.storage_server.get(share_id) if share_list_string == None: share_list = [user] else: share_list_string = self.check_integrity_and_get_value( ka, share_id) share_list = util.from_json_string(share_list_string) share_list.append(user) share_list_string = util.to_json_string(share_list) self.MAC_and_store(share_list_string, ka, share_id) self.share_keys_with_user(user, encrypted_original_filename, keys) self.make_bridge(user, encrypted_original_filename) keys_filename = (ka, ke, encrypted_original_filename) keys_filename_string = util.to_json_string(keys_filename) encrypted_keys_filename_string = self.crypto.asymmetric_encrypt( keys_filename_string, self.pks.get_public_key(user)) signed_encrypted_keys_filename_string = self.crypto.asymmetric_sign( encrypted_keys_filename_string, self.private_key) msg = util.to_json_string((encrypted_keys_filename_string, signed_encrypted_keys_filename_string)) return msg
def __init__(self, storage_server, public_key_server, crypto_object, username): super().__init__(storage_server, public_key_server, crypto_object, username) self.threshold = 128 k1 = path_join(self.username, "dir_keys") k2 = path_join(self.username, "dir") k3 = path_join(self.username, "sdir_keys") k4 = path_join(self.username, "sdir") # We only create a directory for the user if this is the first time the user uses the client if self.storage_server.get(k1) is None and self.storage_server.get( k2) is None: # Create keys to encrypt directory for user enc_key = self.crypto.get_random_bytes(16) mac_key = self.crypto.get_random_bytes(16) # Grab user's public key pub_key = self.pks.get_public_key(self.username) # Generate the encryption of the keys as well as the signature for it encryption = self.crypto.asymmetric_encrypt( enc_key + mac_key, pub_key) sig = self.crypto.asymmetric_sign(encryption, self.private_key) # Store the keys and their signature in the storage server self.storage_server.put(k1, encryption + sig) # Generate the encryption of the directory as well as a mac for it directory = {} toStore = e_and_m(self.crypto, enc_key, mac_key, to_json_string(directory)) self.storage_server.put(k2, toStore) # We only create a sharing directory for the user if this is the first time the user uses the client if self.storage_server.get(k3) is None and self.storage_server.get( k4) is None: # Create keys to encrypt directory for user enc_key = self.crypto.get_random_bytes(16) mac_key = self.crypto.get_random_bytes(16) # Grab user's public key pub_key = self.pks.get_public_key(self.username) # Generate the encryption of the keys as well as the signature for it encryption = self.crypto.asymmetric_encrypt( enc_key + mac_key, pub_key) sig = self.crypto.asymmetric_sign(encryption, self.private_key) # Store the keys and their signature in the storage server self.storage_server.put(k3, encryption + sig) # Generate the encryption of the sharing directory as well as a mac for it sdirectory = {} toStore = e_and_m(self.crypto, enc_key, mac_key, to_json_string(sdirectory)) self.storage_server.put(k4, toStore)
def share(self, user, name): self.get_dir() if not name in self.dir: # file not part of user's dir return None file_record = self.dir[name] target_pub_key = self.pks.get_public_key(user) if not target_pub_key: # can't find user to share with return None # generate new share record loc = self.crypto.get_random_bytes(32) enc_key = self.crypto.get_random_bytes(32) mac_key = self.crypto.get_random_bytes(32) share_record = { 'loc': loc, 'enc_key': enc_key, 'mac_key': mac_key, } file_record['shared'][user] = share_record self.upload_dir() # create and upload a gateway file gateway_record = { 'loc': file_record['loc'], 'enc_key': file_record['enc_key'], 'mac_key': file_record['mac_key'], 'is_leaf': not file_record['is_gateway'] } value = to_json_string(gateway_record) self.put(value, loc, enc_key, mac_key) # construct sharing message value = to_json_string(share_record) iv = self.crypto.get_random_bytes(16) enc_key = self.crypto.get_random_bytes(32) enc_value = self.sym_enc(value, iv, enc_key) enc_enc_key = self.crypto.asymmetric_encrypt(enc_key, target_pub_key) msg = { 'enc_value': enc_value, 'iv': iv, 'enc_enc_key': enc_enc_key, 'sig': self.crypto.asymmetric_sign(enc_enc_key + iv + enc_value, self.private_key) } return to_json_string(msg)
def receive_share(self, from_username, newname, message): """Agrees to the access granted from from_username and user will access this file using the filename newname. First, we create a mapping from newname to an (id, encryption_key, mac_key) and store it into user's directory. Then, we store the id : sharename mapping into the server. Recall that sharename is a [P]. """ if message is not None: # Make sure that something is really shared to us # Grab the directory keys of user keys1 = self.grab_directory_keys() enc_key1 = keys1[0] mac_key1 = keys1[1] # Grab the sharing directory of this user keys2 = self.grab_sdirectory_keys() enc_key2 = keys2[0] mac_key2 = keys2[1] # Grab the directories of using the keys above directory = self.grab_directory(enc_key1, mac_key1) sdirectory = self.grab_sdirectory(enc_key2, mac_key2) # Verify the message msg = message[:512] sig = message[512:] # Test if our message aren't messed with if not self.crypto.asymmetric_verify( msg, sig, self.pks.get_public_key(from_username)): raise IntegrityError # If we reach here, we have verified that our message are good decrypted_value = self.crypto.asymmetric_decrypt( msg, self.private_key) share_id = decrypted_value[:32] share_ekey = decrypted_value[32:64] # Got directory encryption key share_mkey = decrypted_value[64:] # Got directory mac key # Generate (file_id, encryption_key, mac_key) tuple file_id = self.crypto.get_random_bytes(16) tup = (file_id, share_ekey, share_mkey) # Store a mapping of newname : tuple into directory, encrypt the directory and then store it into the server directory[ newname] = tup # Replaces tup at newname even if it already has a value toStore = e_and_m(self.crypto, enc_key1, mac_key1, to_json_string(directory)) k1 = path_join(self.username, "dir") self.storage_server.put(k1, toStore) # Store a mapping of id : sharename_pointer into the storage server self.storage_server.put(file_id, "[P] " + share_id) # Create an empty dictionary under this filename for our sharing directory sdirectory[newname] = {} toStore = e_and_m(self.crypto, enc_key2, mac_key2, to_json_string(sdirectory)) k2 = path_join(self.username, "sdir") self.storage_server.put(k2, toStore)
def revoke(self, user, name): """This method basically allows user to revoke any other user that he/she shared the file with. Once revoked, that user and every other person that he/she shared this file with will no longer have access to the destination of the share chain, i.e. the real copy of the file. """ # Grab the directory keys of user keys1 = self.grab_directory_keys() enc_key1 = keys1[0] mac_key1 = keys1[1] # Grab the sharing directory of this user keys2 = self.grab_sdirectory_keys() enc_key2 = keys2[0] mac_key2 = keys2[1] # Grab the directories of using the keys above directory = self.grab_directory(enc_key1, mac_key1) sdirectory = self.grab_sdirectory(enc_key2, mac_key2) # Download our file and update our directory so that we can correctly upload our file again content = self.download(name) directory.pop(name) toStore = e_and_m(self.crypto, enc_key1, mac_key1, to_json_string(directory)) k1 = path_join(self.username, "dir") self.storage_server.put(k1, toStore) self.upload(name, content) # Re-grab our directory directory = self.grab_directory(enc_key1, mac_key1) # Grab the tuple corresponding to the filename name tup = directory.get(name) if tup is None: # Case when such tuple doesn't exist. Nothing to share here return None else: # Case when such a tuple does exist # Grab the id that corresponds to this filename in the user's directory as well as the keys new_file_id, new_ekey, new_mkey = tup[0], tup[1], tup[2] # We delete user from our updates list and update the others d = sdirectory.get(name) d.pop(user) for k, v in d.items(): share_id = v[0] share_ekey = v[1] share_mkey = v[2] toStore = e_and_m(self.crypto, share_ekey, share_mkey, new_file_id + new_ekey + new_mkey) self.storage_server.put(share_id, toStore) # Update our sharing directory with the revoked user revoked sdirectory[name] = d toStore = e_and_m(self.crypto, enc_key2, mac_key2, to_json_string(sdirectory)) name = path_join(self.username, "sdir") self.storage_server.put(name, toStore)
def revoke(self, user, name): value = self.download(name) if not value: return False file_record = self.dir[name] shares = file_record['shared'] # check to make sure we've shared with that user if not user in shares: return False else: shares.pop(user) # re-encrypt and upload the file again new_mac_key = self.crypto.get_random_bytes(32) new_enc_key = self.crypto.get_random_bytes(32) file_record['enc_key'] = new_enc_key file_record['mac_key'] = new_mac_key # upload actual file merkle = self.create_merkle(value) file_meta = { 'length': len(value), 'tree': merkle.loc, } self.upload_merkle(merkle, new_enc_key, new_mac_key) file_meta_value = to_json_string(file_meta) self.put(file_meta_value, file_record['loc'], new_enc_key, new_mac_key) self.upload_dir() for u in shares: share_record = shares[u] loc = share_record['loc'] enc_key = share_record['enc_key'] mac_key = share_record['mac_key'] gateway_record = { 'loc': file_record['loc'], 'enc_key': new_enc_key, 'mac_key': new_mac_key, 'is_leaf': not file_record['is_gateway'] } value = to_json_string(gateway_record) self.put(value, loc, enc_key, mac_key) return True
def receive_share(self, from_username, newname, message): #print(message) message_as_list = util.from_json_string(message) sharename = message_as_list[0] data_key = message_as_list[1] data_mac_key = message_as_list[2] dictionary = None uid = self.resolve(path_join(self.username, newname)) random_id = self.crypto.get_random_bytes(16) random_key_for_value = self.crypto.get_random_bytes(16) random_key_for_dictionary = self.crypto.get_random_bytes(16) random_key_for_value_mac = self.crypto.get_random_bytes(16) random_key_for_dict_mac = self.crypto.get_random_bytes(16) value_iv = self.crypto.get_random_bytes(16) encrypted_random_key_for_dictionary = self.crypto.asymmetric_encrypt( random_key_for_dictionary, self.private_key.publickey()) username_keys = path_join(self.username, "dict_keys") username_dictionary = path_join(self.username, "dictionary") if self.storage_server.get(username_keys) is None: self.storage_server.put(username_keys, encrypted_random_key_for_dictionary) else: e_random_key_for_dictionary = self.storage_server.get( username_keys) random_key_for_dictionary = self.crypto.asymmetric_decrypt( e_random_key_for_dictionary, self.private_key) dictionary = self.retrieve_dict() dictionary[path_join(self.username, newname)] = [ random_id, random_key_for_value, random_key_for_value_mac, data_key, data_mac_key ] dictionary_iv = self.crypto.get_random_bytes(16) dictionary_as_string = util.to_json_string(dictionary) dictionary_encrypt = self.crypto.symmetric_encrypt( dictionary_as_string, random_key_for_dictionary, 'AES', 'CBC', dictionary_iv) dictionary_encrypt_mac = self.crypto.message_authentication_code( dictionary_encrypt, random_key_for_dict_mac, 'SHA256') list_of_items = [ dictionary_iv, dictionary_encrypt, dictionary_encrypt_mac ] list_of_items_as_string = util.to_json_string(list_of_items) self.storage_server.put(username_dictionary, list_of_items_as_string) #my_id = path_join(self.username, newname) my_id = random_id self.storage_server.put( my_id, "[POINTER] " + sharename) #message[i] if we add more stuff to message
def share(self, user, name): # GET DIRECTORY KEYS directory_keys = self.get_directory_keys() sym_ke, sym_ka = directory_keys # GET DIRECTORY client_ID = path_join(self.username, "directory") resp = self.storage_server.get(client_ID) if resp is None: return None directory = self.decrypt_directory(resp, sym_ke, sym_ka) if name not in directory: return None file = directory[name] # directory[name] = {"keys": (keys, session_key), "shared": [], "file_id": self.crypto.get_random_bytes(16)}} # owner sharing w/ child if len(file["file_id"]) == 32: keys = file["keys"][0] session_key = file["keys"][1] file_id = path_join(user, self.username, file["file_id"]) self.encrypt_filepath(file_id, session_key, keys, name) # directory[name] = {"keys": session_key, "shared": [], "file_id": B/A/random 16 bytes} # child sharing w/ grandchild else: file_id = file["file_id"] session_key = file["keys"] directory[name]["shared"].append(user) self.encrypt_directory(client_ID, directory, sym_ke, sym_ka) # cache directory self.directory[name]["shared"].append(user) # ENCRYPT MESSAGE TO SEND recipient_pub_key = self.pks.get_public_key(user) share_info = {"session_key": session_key, "file_id": file_id} share_info = util.to_json_string(share_info) crypted = self.crypto.asymmetric_encrypt(share_info, recipient_pub_key) sign = self.crypto.asymmetric_sign(crypted, self.private_key) output = (crypted, sign) output = util.to_json_string(output) return output
def share(self, user, name): # Replace with your implementation (not needed for Part 1) uid = path_join(self.username, name) username_keys = path_join(self.username, "dict_keys") username_dictionary = path_join(self.username, "dictionary") random_key_for_dictionary = self.storage_server.get(username_keys) #print(random_key_for_dictionary) random_key_for_dictionary = self.crypto.asymmetric_decrypt(random_key_for_dictionary, self.private_key) dictionary_items_as_string = self.storage_server.get(username_dictionary) #print(dictionary_items_as_string) if dictionary_items_as_string is None: return None dictionary_items_as_list = util.from_json_string(dictionary_items_as_string) dictionary_iv = dictionary_items_as_list[0] encrypted_dictionary = dictionary_items_as_list[1] decrypted_dictionary = self.crypto.symmetric_decrypt(encrypted_dictionary, random_key_for_dictionary, 'AES', 'CBC', dictionary_iv) actual_dictionary = util.from_json_string(decrypted_dictionary) random_keys = actual_dictionary.get(uid) #print(random_keys) if random_keys is None: return None random_id = random_keys[0] random_id_key = random_keys[1] random_id_mac = random_keys[2] e_key = self.crypto.asymmetric_encrypt(random_id_key, self.public_key_server.get_public_key(user)) if self.storage_server.get(random_id+"shared_file") == None: shared_dict_as_string = util.to_json_string({self.username: None}) #SHADYYYYYYYYYYY; how do you initialize shizzzzzzzz #don't need to encrypt shared_dict since it's public info shared_dict_mac = self.crypto.message_authentication_code(shared_dict_as_string, random_id_key, 'SHA256') shared_dict_values = [shared_dict_as_string, shared_dict_mac] shared_dict_values_as_string = util.to_json_string(shared_dict_values) self.storage_server.put(random_id+"shared_file", shared_dict_values_as_string) shared_dict = self.storage_server.get(random_id+"shared_file") calculated_mac = self.crypto.message_authentication_code(shared_dict, random_id_key, 'SHA256') if calculated_mac != shared_dict[1]: raise IntegrityError() #is this the right error shared_dict = util.from_json_string(shared_dict) shared_dict[self.username] = shared_dict[self.username].append({user: None}) msg_as_list = [random_id, e_key, random_id+"shared_file"] msg_as_string = util.to_json_string(msg_as_list) #they're not gonna test if you call share on something you don't own #return None if a user tries to download a file that they don't have access to, not IntegrityError() return msg_as_string
def encrypt_directory(self, client_ID, directory, sym_ke, sym_ka): directory = util.to_json_string(directory) IV = self.crypto.get_random_bytes(16) encrypted_dir = self.crypto.symmetric_encrypt(directory, sym_ke, 'AES', 'CBC', IV) signed_dir = self.crypto.message_authentication_code( encrypted_dir, sym_ka, 'SHA256') directory_info = { "IV": IV, "encrypted_keys": encrypted_dir, "signed_keys": signed_dir } self.storage_server.put(client_ID, util.to_json_string(directory_info))
def init_dir_keys(self): self.dir_keys_loc = self.username + '/dir_keys' value = self.storage_server.get(self.dir_keys_loc) if not value: # key not already on the server self.dir_enc_key = self.crypto.get_random_bytes(32) self.dir_mac_key = self.crypto.get_random_bytes(32) dir_keys = { 'dir_enc_key': self.dir_enc_key, 'dir_mac_key': self.dir_mac_key } dir_keys_str = to_json_string(dir_keys) enc_value = self.crypto.asymmetric_encrypt(dir_keys_str, self.private_key) sig = self.crypto.asymmetric_sign(self.dir_keys_loc + enc_value, self.private_key) dir_keys_pkg = {'enc_value': enc_value, 'sig': sig} value = to_json_string(dir_keys_pkg) if not self.storage_server.put(self.dir_keys_loc, value): # unable to upload sym_key to storage server raise IntegrityError else: # keys fetched from server try: dir_keys_pkg = from_json_string(value) sig = dir_keys_pkg['sig'] enc_value = dir_keys_pkg['enc_value'] if not self.crypto.asymmetric_verify( self.dir_keys_loc + enc_value, sig, self.private_key): raise IntegrityError dir_keys_str = self.crypto.asymmetric_decrypt( enc_value, self.private_key) dir_keys = from_json_string(dir_keys_str) self.dir_enc_key = dir_keys['dir_enc_key'] self.dir_mac_key = dir_keys['dir_mac_key'] except (ValueError, TypeError, KeyError, CryptoError): # malformed key package raise IntegrityError
def hashTree(self, ID, d, sym_ke, sym_ka): tree = {} if len(d.keys()) == 1: return d for i in d.keys(): if i % 2 == 0: # even binary tree if i + 1 in d: cipher = self.crypto.cryptographic_hash( d[i] + d[i + 1], 'SHA') #SHA # odd binary tree else: cipher = self.crypto.cryptographic_hash(d[i], 'SHA') #SHA path = path_join(ID, str(i // 2)) mac = self.crypto.message_authentication_code( cipher, sym_ka, 'SHA') #SHA cipher_info = {"hash": cipher, "mac": mac} self.storage_server.put(path, util.to_json_string(cipher_info)) tree[i // 2] = cipher return self.hashTree(ID, tree, sym_ke, sym_ka)
def MAC_and_store_2(self, value_string, ka, data_id): MACed_value_string = self.crypto.message_authentication_code( value_string, ka, "MD5") half = int(len(MACed_value_string) / 4) all_value = (value_string, MACed_value_string[:half]) all_value_string = util.to_json_string(all_value) self.storage_server.put(data_id, all_value_string)
def make_file_keys(self, fid): ka = self.crypto.get_random_bytes(16) ke = self.crypto.get_random_bytes(16) keys = (ka, ke) keys_string = util.to_json_string(keys) self.sign_and_store(keys_string, self.username, fid) return keys
def receive_share(self, from_username, newname, message): """Agrees to the access granted from from_username and user will access this file using the filename newname. First, we create a mapping from newname to an (id, encryption_key, mac_key) and store it into user's directory. Then, we store the id : sharename mapping into the server. Recall that sharename is a [P]. """ if message is not None: # Make sure that something is really shared to us # Grab the directory keys of user keys = self.grab_directory_keys() enc_key = keys[0] mac_key = keys[1] # Grab the directory using the keys above directory = self.grab_directory(enc_key, mac_key) # Generate (file_id, encryption_key, mac_key) tuple file_id = self.crypto.get_random_bytes(16) e_key = message[1] m_key = message[2] tup = (file_id, e_key, m_key) # Store a mapping of newname : tuple into directory, encrypt the directory and then store it into the server directory[ newname] = tup # Replaces tup at newname even if it already has a value iv = self.crypto.get_random_bytes(16) enc = self.crypto.symmetric_encrypt(to_json_string(directory), enc_key, 'AES', 'CBC', iv) mac = self.crypto.message_authentication_code( iv + enc, mac_key, 'SHA256') name = path_join(self.username, "dir") self.storage_server.put(name, iv + enc + mac) # Store a mapping of id : sharename_pointer into the storage server k = path_join(self.username, "files", file_id) self.storage_server.put(k, "[P] " + message[0])
def revoke(self, user, name): """This method basically allows user to revoke any other user that he/she shared the file with. Once revoked, that user and every other person that he/she shared this file with will no longer have access to the destination of the share chain, i.e. the real copy of the file. """ # Grabs the sharing directory keys of user keys = self.grab_sdirectory_keys() enc_key = keys[0] mac_key = keys[1] # Grabs the sharing directory of user sdirectory = self.grab_sdirectory(enc_key, mac_key) # Grabs the file id of the corresponding user + name combo and make sure that it exists file_id = sdirectory.get(user + name) if file_id is not None: # We are only able to revoke a user of a file if it exists # Generate the sharename that user wants to delete sharename = path_join(self.username, "sharewith", user, file_id) # Delete the sharename so that the shared user and the people they shared with cannot reach the destination # of the share chain anymore self.storage_server.delete(sharename) # Remove this sharing instance from the sdirectory and store it back into the storage server sdirectory.pop(user + name) iv = self.crypto.get_random_bytes(16) enc = self.crypto.symmetric_encrypt(to_json_string(sdirectory), enc_key, 'AES', 'CBC', iv) mac = self.crypto.message_authentication_code( iv + enc, mac_key, 'SHA256') name = path_join(self.username, "sdir") self.storage_server.put(name, iv + enc + mac)
def upload_dir(self): iv = self.crypto.get_random_bytes(16) dir_str = to_json_string(self.dir) enc_value = self.sym_enc(dir_str, iv, self.dir_enc_key) dir_pkg = { 'iv': iv, 'mac': self.mac(self.dir_loc + iv + enc_value, self.dir_mac_key), 'enc_value': enc_value } value = to_json_string(dir_pkg) if not self.storage_server.put(self.dir_loc, value): # need to keep dir updated at all times raise IntegrityError
def fetch_and_decrypt(self, encrypted_id, key_encrypt, key_auth): string_data = self.storage_server.get(encrypted_id) ##print(string_data) if string_data is None: return None, None try: encrypt_node, sign_encrypt_node, file_iv = util.from_json_string( string_data) except ValueError: raise IntegrityError # Check encrypt_key_node signature string_encrypt_node = util.to_json_string([encrypt_node, file_iv]) new_auth_encrypt_node = self.crypto.message_authentication_code( string_encrypt_node, key_auth, 'SHA512') if new_auth_encrypt_node != sign_encrypt_node: raise IntegrityError # Decrypt encrypt_key_node json_data = self.crypto.symmetric_decrypt(encrypt_node, key_encrypt, 'AES', 'CBC', IV=file_iv) data = util.from_json_string(json_data) if len(data) == 4 and data[3] == "node": data = self.node(data[0], data[1], data[2]) elif len(data) == 6 and data[5] == "merkle-node": data = self.merkle_node(data[0], data[1], data[2], data[3], data[4]) return data, file_iv
def upload_merkle(self, node, enc_key, mac_key, root=True): node_value = { 'hash': node.hash, 'left': node.left.loc if node.left else None, 'right': node.right.loc if node.right else None, 'iv': None, 'data': None } if node.data: node_value['iv'] = node.iv node_value['data'] = self.sym_enc(node.data, node.iv, enc_key) value = to_json_string(node_value) if root: self.put_no_enc(value, node.loc, mac_key) else: self.storage_server.put(node.loc, value) if not node.data: if node.left: self.upload_merkle(node.left, enc_key, mac_key, False) if node.right: self.upload_merkle(node.right, enc_key, mac_key, False)
def hashData(self, ID, message, sym_ke, sym_ka): IV = self.crypto.get_random_bytes(16) encrypted_message = self.crypto.symmetric_encrypt( message, sym_ke, 'AES', 'CBC', IV) mac = self.crypto.message_authentication_code(encrypted_message + ID, sym_ka, 'SHA256') message_info = {"IV": IV, "encrypted": encrypted_message, "mac": mac} self.storage_server.put(ID, util.to_json_string(message_info))
def sign_and_store(self, value_string, user, data_id): encrypted_value_string = self.crypto.asymmetric_encrypt( value_string, self.pks.get_public_key(user)) signed_encrypted_value_string = self.crypto.asymmetric_sign( encrypted_value_string, self.private_key) all_value = (encrypted_value_string, signed_encrypted_value_string) all_value_string = util.to_json_string(all_value) self.storage_server.put(data_id, "[DATA] " + all_value_string)
def safe_encrypt(self, keys): pub_key = self.private_key.publickey() key_str = util.to_json_string(keys) encrypted_keys = self.crypto.asymmetric_encrypt(key_str, pub_key) signed_keys = self.crypto.asymmetric_sign(encrypted_keys, self.private_key) return {"encrypted_keys": encrypted_keys, "signed_keys": signed_keys}
def receive_share(self, from_username, newname, message): # # Replace with your implementation (not needed for Part 1) # raise NotImplementedError if self.storage_server.get(self.username + "/shared") is None: dictionary = {newname : (message[1], from_username, message[0])} else: dictionary = self.storage_server.get(self.username + "/shared") dictionary[newname] = (message[1], from_username, message[0]) self.storage_server.put(self.username + "/shared", util.to_json_string(dictionary))
def AES_CBC_and_store(self, string, keys, uid): ka, ke = keys IV = self.crypto.get_random_bytes(16) cipher_string = self.crypto.symmetric_encrypt(string, ke, "AES", "CBC", IV) tag = self.crypto.message_authentication_code(IV + cipher_string + uid, ka, "MD5") cipher_all = (IV, cipher_string, tag) cipher_all_string = util.to_json_string(cipher_all) self.storage_server.put(uid, "[DATA] " + cipher_all_string)
def share(self, user, name): share_file = None if self.storage_server.get(path_join(self.username, "share_file", name)) is None: share_file = [] else: share_file_as_string = self.storage_server.get( path_join(self.username, "share_file", name)) share_file = util.from_json_string(share_file_as_string) share_file.append(user) share_file_as_string = util.to_json_string(share_file) self.storage_server.put(path_join(self.username, "share_file", name), share_file_as_string) uid = self.resolve(path_join(self.username, name)) sharename = path_join("[SHARE]", self.username, "sharewith", user, name) if uid.startswith("[SHARE]"): shared_info = self.get_shared_random_shit(uid) #encrypt the shared_info self.storage_server.put( sharename, "[POINTER] " + path_join(self.username, name)) return sharename #msg = [sharename] dictionary = self.retrieve_dict() random_keys = dictionary.get(path_join(self.username, name)) if random_keys is None: #when you try to share something you don't have access to; get rid of this? return None random_id = random_keys[0] random_key_for_value = random_keys[1] random_key_for_value_mac = random_keys[2] message = [random_id, random_key_for_value, random_key_for_value_mac] message_as_string = util.to_json_string(message) self.storage_server.put(sharename, "[DATA] " + message_as_string) return sharename
def receive_share(self, from_username, newname, message): # Replace with your implementation (not needed for Part 1) ''' d_key = self.storage_server.get("dict_key") dictionary_items_as_string = self.storage_server.get("dict") dictionary_items_as_list = util.from_json_string(dictionary_items_as_string) the_iv = dictionary_items_as_list[0] dictionary = dictionary_items_as_list[1] dictionary_signature = dictionary_items_as_list[2] dictionary = self.crypto.symmetric_decrypt(dictionary, d_key, 'AES', 'CBC', the_iv) dictionary = util.from_json_string(dictionary) random_id = self.crypto.get_random_bytes(16) random_key_for_value = self.crypto.get_random_bytes(16) dictionary[uid] = (random_id, random_key_for_value) ''' d_key = self.storage_server.get("dict_key") dictionary_items_as_string = self.storage_server.get("dict") dictionary_items_as_list = util.from_json_string(dictionary_items_as_string) the_iv = dictionary_items_as_list[0] dictionary = dictionary_items_as_list[1] dictionary_signature = dictionary_items_as_list[2] dictionary = self.crypto.symmetric_decrypt(dictionary, d_key, 'AES', 'CBC', the_iv) dictionary = util.from_json_string(dictionary) from_users_random_id = dictionary.get(path_join(from_username, newname)) my_id = path_join(self.username, newname) dictionary[my_id] = from_users_random_id dictionary_iv = self.crypto.get_random_bytes(16) string_dict = util.to_json_string(dictionary) dictionary_encrypt = self.crypto.symmetric_encrypt(string_dict, d_key, 'AES', 'CBC', dictionary_iv) list_of_items = [dictionary_iv, dictionary_encrypt, 'LOL'] list_of_items_as_string = util.to_json_string(list_of_items) self.storage_server.put("dict", list_of_items_as_string) self.storage_server.put(my_id, "[POINTER] " + message)
def put_no_enc(self, value, loc, mac_key): pkg = { 'mac': self.mac(loc + value, mac_key), 'value': value, } value = to_json_string(pkg) if not self.storage_server.put(loc, value): # already updated directory but can't upload file return False return True
def get_directory_keys(self): dir_ID = path_join("information", self.username) resp = self.storage_server.get(dir_ID) if resp is None: keys = self.dir_keys() key_info = self.safe_encrypt(keys) self.storage_server.put(dir_ID, util.to_json_string(key_info)) else: keys = self.safe_decrypt(resp) return keys
def share(self, user, name): """Creates an intermediate sharename that can be deleted only by the user since it is tied to the id that is in the directory of this user. Then, stores a mapping of the sharename to a pointer that will links to the destination of the real file. Returns a tuple with sharename and the keys needed to update or download this file. """ # Grab the directory keys of user keys1 = self.grab_directory_keys() enc_key1 = keys1[0] mac_key1 = keys1[1] # Grab the sharing directory of this user keys2 = self.grab_sdirectory_keys() enc_key2 = keys2[0] mac_key2 = keys2[1] # Grab the directories of using the keys above directory = self.grab_directory(enc_key1, mac_key1) sdirectory = self.grab_sdirectory(enc_key2, mac_key2) # Grab the tuple corresponding to the filename name tup = directory.get(name) if tup is None: # Case when such tuple doesn't exist. Nothing to share here return None else: # Case when such a tuple does exist # Grab the id that corresponds to this filename in the user's directory as well as the keys file_id, e_key, m_key = tup[0], tup[1], tup[2] share_id = self.crypto.get_random_bytes(16) share_ekey = self.crypto.get_random_bytes(16) share_mkey = self.crypto.get_random_bytes(16) toStore = e_and_m(self.crypto, share_ekey, share_mkey, file_id + e_key + m_key) self.storage_server.put(share_id, toStore) # Store this sharing information into our sharing directory d = sdirectory[name] d[user] = (share_id, share_ekey, share_mkey) sdirectory[name] = d # Update this sharing directory back to the storage server toStore = e_and_m(self.crypto, enc_key2, mac_key2, to_json_string(sdirectory)) self.storage_server.put(path_join(self.username, "sdir"), toStore) dst_pk = self.pks.get_public_key(user) msg = self.crypto.asymmetric_encrypt( share_id + share_ekey + share_mkey, dst_pk) sig = self.crypto.asymmetric_sign(msg, self.private_key) return msg + sig