This short sample program should give you an idea what is and how to use libencio.
#include <stdio.h>
#include "encio.h"
int main(int argc, char **argv)
{
ENCFILE *ef;
char buf[100];
char *passphrase = "acomplicatedpassphrase";
/* open an file encrypted with passphrase */
ef = enc_fopen("test.txt.nc", "rb", passphrase);
enc_add_index(ef, "test.txt.ix", passphrase,
INDEX_LOAD | INDEX_CREATE | INDEX_SAVE);
/* read first 100 bytes of the encrypted data*/
enc_fread(ef, 1, buf, 100);
printf("First 100 bytes of the file: %s", ef);
/* read last 100 bytes of the encrypted data */
enc_fseek(ef, -100, SEEK_SET);
enc_fread(ef, 1, buf, 100);
printf("Last 100 bytes of the file: %s", ef);
enc_fclose(ef);
}
In the sample, we assume that we have a file named test.txt.nc which
has been symmetrically encrypted with passphrase "acomplicatedpassphrase".
enc_fopen() opens the file for reading, just as fopen() would
open a non-encrypted counterpart. The difference, compared to stdio
fopen() call, is a third parameter through which you supply the passphrase
for decryption. All other libencio functions in the example function
as their stdio counterparts.
The other difference from stdio is that a call to
enc_add_index() is required in order to support random seeking of the
file. This is needed because in most encryption modes considered secure (eg,
feedback modes - CFB), in order to decrypt n-th byte of a
file, one must decrypt all preceeding bytes as well. In the worst case
scenario – a seek to the last byte in the file – the complete file must be
decrypted. Such an implementation of seeking would be unacceptably
timeconsuming for large files.
libencio handles this by creating an "encryption state index"
(ENCINDEX) on the file - a snapshot of decryption engine state (usually, the
feedback register, FR), at predefined locations ("bookmarks") in the
file (usually, every blocksize bytes, where by default
blocksize = 1024). This allows libencio to quickly resume
decryption starting from the bookmark nearest to the requested seek
location. The worst case scenario in seeking with an index is a required
decryption of blocksize-1 bytes, which is usually acceptable.
Memory required for an index is proportional to
(fsize/blocksize)*FR_size where fsize is the encrypted file
size and FR_size is the size of the feedback register for the cipher mode.
For example, using 256 bit AES cipher requires 32 bytes per bookmark, which
for a 500MB file and one bookmark per kb (blocksize = 1024),
will generate a 16MB encryption state index. Increasing the blocksize
will reduce the ENCINDEX footprint, but will degrade the seek performance.
ENCINDEX can (and should, for frequently accessed files) be saved to speed
up construction on subsequent openings of the file. When and ENCINDEX is
saved, it is encrypted with the same passphrase as the file which it
indexes. The index is saved by adding an INDEX_SAVE flag as the
fourth parameter of the enc_add_index() call. It can be subsequently
loaded by specifying the INDEX_LOAD flag.