Diseba: a distributed and secure backup (take II)
Continuing on the idea of a solution for distributed and secure backup, I have now a more clear view of the software. Compared to my first original idea, I changed some details. However the cryptographic details could be kept as is. And I have found a name for the project: diseba. :)Overview
The general idea is the same as in my first note: save the content of your hard disk on your friends' hard-disks, in such a way that only you can read those copies (through strong encryption). Moreover, the network of friends is closed (i.e. you must agree with the others to enter the "club"). The main idea is to divide the backup into two main steps: storing the content to backup into a set of encrypted blocks and then distributing those encrypted blocks onto the hard-disks of your friends. More specifically, a backup phase is divided into four steps:- Determine which files are new or updated;
- Cut them in fixed size and encrypted blocks, on local disk, along with a Master Index that contains all needed information to restore a backup;
- Save those blocks on the remote hard-disks, distributing enough copies to ensure long term availability. Two methods could be used: rsync or a bittorrent-like distribution;
- Send to remote nodes the list of blocks and master index we want to keep, all other blocks or master indexes for this node being erased.
- If the file belongs to an exclusion list (with glob operators, like "*~"), it is excluded from the list of files to save;
- The last modification date and size is compared to the last backup to see if it needs a new backup;
- If the file is guessed to be already compressed from its suffix, like images (.png, .jpg), compressed files (.gz, .zip, .tgz) or video and music (.mp3, .mp4, .ogg, .flac), it is not compressed;
- Each file or link is compressed, added a MAC (Message Authentication Code), cut into fixed size blocks (1024 bytes) and all blocks are encrypted with an IV (Initialization Vector) at the begining of the first block.
+------------------+ +------------------+ +------------------+
|IV| file content | | file content | | file content |MAC|
+------------------+ +------------------+ +------------------+
encrypted block encrypted block encrypted block
Content of the Master Index
The Master Index is a password encrypted compressed file that contains all the information needed to restore a backup from a set of encrypted blocks. More specifically, it contains:- local node number;
- private and public SSL key of this node;
- a reference to a possible previous Master Index;
- a master key that allows to derive both encryption/decryption and MAC keys. This master key is generated freshly for each new master index;
- a 64-bits counter used to number blocks and master indexes. This counter is copied from one master index to the other (i.e. its value is kept along the lifetime of the backups);
- a table of saved files, index by file/directory path. For
directories, links and tiny files (a few bytes), their content is
stored directly in the Master Index. Small files (compressed size
smaller than a block) are stored as several grouped in a block. Otherwise
a regular file is divided into a range of blocks. Each line of this
table contains, depending on the type of the file:
- for directories:
- Access rights;
- User id of the owner;
- Group ID of the directory's group;
- Last access time;
- Last modification time;
- Last status change time;
- for tiny files and links (a few bytes, to small to gain size from
compression, so they are stored within master index):
- Access rights;
- User id of the owner;
- Group ID of the file or link's group;
- Last access time;
- Last modification time;
- Last status change time;
- File or link content with its type;
- for small files or links (compressed size smaller that a block,
so several of them can be saved into a single block):
- Access rights;
- User id of the owner;
- Group ID of the file or link's group;
- Last access time;
- Last modification time;
- Last status change time;
- An entry number into the table of grouped file/link blocks (see below);
- for regular files:
- Access rights;
- User id of the owner;
- Group ID of the file's group;
- Last access time;
- Last modification time;
- Last status change time;
- Range of blocks identifiers containing the file;
- File's compressed size;
- MAC of the file;
- for directories:
- a table of grouped file/link blocks, for blocks containing several
files. Each entry in this table stores:
- block identifier of the block containing the files or links;
- MAC of the group of files/links;
- The list of all files into this block;
- For each file or link: type, offset and length within the block;
On disk backup structure
The backup on the local disk has following hierarchy:
node0/master_index/1 <-- saved master index #1
node0/master_index/5
node0/backup_state <-- local status of the software in case of interruption
node0/blocks/0/40
node0/blocks/0/80 <-- encrypted blocks as 1 KB files
:
node0/blocks/f/67f
|
+---- the set of blocks are divided into 16 directories, 0 to f
node1/ <-- same directory structure as for node0
:
node5/
Remote copy of blocks and master indexes
Once a new backup (blocks and master index) has been generated on local disk, one needs to save it on remote nodes. We propose to use two strategies:- rsync synchronisation of the disk directory structure. This would be not efficient with several remote nodes but it could be quite useful on a local network (and simple to implement ;) ;
- a bittorrent like approach.
- first copy: complete copy from node 0 to node 1;
- second copy: 1/2 copy from node 0 to node 2, 1/2 copy from node 1 to node 2;
- ...
- Nth copy: 1/N copy from node 0 to node N-1, ..., 1/N copy from node N-2 to node N-1.
trigger_block_copy([list of source nodes], [list of block ids])
=> returns success or failure for each block
trigger_master_index_copy([list of source nodes], master_index_id)
=> returns success or failure
pull_block_parts([list of (block id, offset, length)])
=> returns, for each requested part, failure or block content
pull_master_index_part(master index id, offset, length)
=> returns failure or master index content
erase_block_list([list of block id])
=> returns success or failure
erase_master_index(master index id)
=> returns success or failure
A source node would call trigger_blocks_copy to request to
one or more nodes a copy of a list of blocks. Each one of the nodes
receiving this call would in turn use pull_block_parts to
get the needed parts from other nodes having a copy of the needed
block. After all new blocks are copied on remote nodes, the source node
can call erase_block_list to erase outdated blocks. The
procedure is the same for master indexes.
In case a destination node crashes in the middle of a copy, the source
node should consider that the copy has failed and it should elect a new
destination node. In case a sending node crashes in the middle of a
copy, the receiving node should erase the corresponding block and report
a failure to the source node.
As the source node sends at backup step 4 the complete list of blocks
and master index it wants to keep, we avoid keeping stale blocks or
partially copied blocks in case of nodes' crashes.
It might appear that a source node cannot save enough copies onto remote
nodes (because they are unavailable): it should attempt to retry those
copies at a latter time.
Clique management
To create a new clique (group of friends making backups between each other), one should:- Ask for a password;
- Create private and public SSL keys;
- Create an empty master index with block counter set to one and relevant crypto material.
- Ask for a password;
- Create private and public SSL keys;
- Create an empty master index with block counter set to one and relevant crypto material;
- Let the user send public key of this node to the owner of remote nodes;
- Open connection to remote nodes.
Few notes on implementation
In order to answer remote node requests asynchronously, the diseba program should be multi-threaded: one thread to make local backup and trigger local to remote copies, one or more threads to fulfil remote nodes' copy requests. I still intend to implement this program in OCaml. ;) RPC over SSL would be used for communication between nodes. Any opinion on this design?2006-03-25T14:27:40Z [] permanent link
