# Copyright (C) 2015 Combox author(s). See AUTHORS. # # This file is part of Combox. # # Combox is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Combox is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Combox (see COPYING). If not, see # . ## Adapted from https://gist.github.com/sekondus/4322469 import base64 import os from combox.config import get_nodedirs from combox.file import (read_file, write_file, read_shards, write_shards, split_data, glue_data, relative_path) from Crypto.Cipher import AES from os import path BLOCK_SIZE = 32 PAD_CHAR = '#' def pad(data): """Pad data such that its length is a multiple of BLOCK_SIZE. """ padding = (BLOCK_SIZE - (len(data) % BLOCK_SIZE)) * PAD_CHAR data += padding return data def encrypt(data, secret): """Encrypt byestream and return cipher. """ aes = AES.new(pad(secret)) cipher = base64.b64encode(aes.encrypt(pad(data))) return cipher def decrypt(cipher, secret): """Decrypt cipher and return data. """ aes = AES.new(pad(secret)) data = aes.decrypt(base64.b64decode(cipher)).rstrip(PAD_CHAR) return data def encrypt_shards(shards, secret): """Encrypt the shards of data and return a list of ciphers. shards: list of shards (string, bytes). secret: top secret passphrase """ ciphers = [] for shard in shards: cipher = encrypt(shard, secret) ciphers.append(cipher) return ciphers def decrypt_shards(ciphers, secret): """Decrypt the ciphered shards and return a list of shards. shards: list of ciphered shards. secret: top secret passphrase """ shards = [] for cipher in ciphers: shard = decrypt(cipher, secret) shards.append(shard) return shards def split_and_encrypt(fpath, config, fcontent=None): """Splits the file, encrypts the shards and writes them to the nodes. fpath: The path to file that has to be split. config: The dictonary containing the combox configuration information. fcontent: Contents of the file at `fpath' (optional). If `fcontent' is None, then this function reads the contents of the file; otherwise it just assumes `fcontent' is the content of the file. """ rel_path = relative_path(fpath, config) # no. of shards = no. of nodes. SHARDS = len(config['nodes_info'].keys()) f = path.join(config['combox_dir'], rel_path) if not fcontent: fcontent = read_file(f) f_shards = split_data(fcontent, SHARDS) # encrypt shards ciphered_shards = encrypt_shards(f_shards, config['topsecret']) # write ciphered shards to disk f_basename = rel_path # gets the list of node' directories. nodes = get_nodedirs(config) write_shards(ciphered_shards, nodes, f_basename) def decrypt_and_glue(fpath, config, write=True): """ Reads encrypted shards, decrypts and glues them. fpath: The path to file that has to be decrypted & glued from the nodes. config: The dictionary containing the combox configuration information. write: If set, writes the reconstructed file's content to disk. """ rel_path = relative_path(fpath, config) f = path.abspath(fpath) f_basename = rel_path # gets the list of node' directories. nodes = get_nodedirs(config) ciphered_shards = read_shards(nodes, f_basename) # decrypt shards f_parts = decrypt_shards(ciphered_shards, config['topsecret']) # glue them together f_content = glue_data(f_parts) if write: # write the glued content to fpath write_file(f, f_content) return f_content