I'm working on an encryption/decryption program using AES encryption and OpenSSL. I set up a FUSE filesystem between two local directories, one is the mirror directory and the other is the mount point, on my linux virtual machine. I am working on modifying the read, write, and create functions in the fuse_operations struct so that when I open and read an encrypted file from the mount point directory, the plaintext should be displayed in the application's window.
I have a function called do_crypt that takes as input a file with text, an output file where the decrypted/encrypted text is supposed to go, an int for decrypting, encrypting, or passing through, and pass phrase to used to complete the actions. The is code is below:
#define BLOCKSIZE 1024
#define FAILURE 0
#define SUCCESS 1
extern int do_crypt(FILE* in, FILE* out, int action, char* key_str){
/* Local Vars */
/* Buffers */
unsigned char inbuf[BLOCKSIZE];
int inlen;
/* Allow enough space in output buffer for additional cipher block */
unsigned char outbuf[BLOCKSIZE + EVP_MAX_BLOCK_LENGTH];
int outlen;
int writelen;
/* OpenSSL libcrypto vars */
EVP_CIPHER_CTX ctx;
unsigned char key[32];
unsigned char iv[32];
int nrounds = 5;
/* tmp vars */
int i;
/* Setup Encryption Key and Cipher Engine if in cipher mode */
if(action >= 0){
if(!key_str){
/* Error */
fprintf(stderr, "Key_str must not be NULL\n");
return 0;
}
/* Build Key from String */
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), NULL,
(unsigned char*)key_str, strlen(key_str), nrounds, key, iv);
if (i != 32) {
/* Error */
fprintf(stderr, "Key size is %d bits - should be 256 bits\n", i*8);
return 0;
}
/* Init Engine */
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv, action);
}
/* Loop through Input File*/
for(;;){
/* Read Block */
inlen = fread(inbuf, sizeof(*inbuf), BLOCKSIZE, in);
if(inlen <= 0){
/* EOF -> Break Loop */
break;
}
/* If in cipher mode, perform cipher transform on block */
if(action >= 0){
if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen))
{
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
}
/* If in pass-through mode. copy block as is */
else{
memcpy(outbuf, inbuf, inlen);
outlen = inlen;
}
/* Write Block */
writelen = fwrite(outbuf, sizeof(*outbuf), outlen, out);
if(writelen != outlen){
/* Error */
perror("fwrite error");
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
}
/* If in cipher mode, handle necessary padding */
if(action >= 0){
/* Handle remaining cipher block + padding */
if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen))
{
/* Error */
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
/* Write remainign cipher block + padding*/
fwrite(outbuf, sizeof(*inbuf), outlen, out);
EVP_CIPHER_CTX_cleanup(&ctx);
}
/* Success */
return 1;
}
The function works fine without using the fuse system. Everything is encrypted/decrypted properly but when I use the read function to decrypt files in the fuse filesystem I get some invalid characters in the output. I've tried 3 text editors to look at the files: sublime reads the output like any other file with no problem; geany won't open the file because it says it doesn't recognize the encoding and there are invalid characters; gedit shows the decrypted output but also some invalid chars represented as '/00/00/00'. I do not know what these characters are. I did some research and I believe them to be null characters but I don't know why they show up when I use the fuse functions and run decrypt but they don't show up in the output when not using it.
I've tried 2 different version for the read function: one way using an in-memory buffer to hold the contents.
static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
(void) fi;
int res;
char fpath[PATH_MAX];
xmp_fullpath(fpath, path);//changes path to mirror directory
FILE *f;
FILE *tmpFile;
tmpFile = tmpfile();
f = fopen(fpath, "r");
do_crypt(f, tmpFile, DECRYPT, XMP_DATA->key_phrase);//function that decrypts/encrypts
rewind(tmpFile);
res = pread(fileno(tmpFile), buf, size, offset);//read the encrypted/decrypted output to the application buffer
fclose(f);
fclose(tmpFile);
return res;
}
The other way creates a temp file before doing encryption/decryption:
int res;
char fpath[PATH_MAX];
xmp_fullpath(fpath, path);
FILE *memstream;
char *membuf;
size_t memlen;
//off_t eob;
memstream = open_memstream(&membuf, &memlen);//create a dynamically allocated buffer in memory
FILE *f = fopen(fpath, "rb");
do_crypt(f, memstream, DECRYPT, XMP_DATA->key_phrase);
fflush(memstream);
fseek(memstream, offset, SEEK_SET);
res = fread(buf, 1, memlen, memstream);
return res;
My questions are:
1) Why am I getting invalid characters '/00/00' which appear to be null characters in my output when trying to decrypt a file?
2) Why am I able to view the file with one text editor but not the other?
Again encryption and pass-through work perfectly in the fuse system and I can open them up with all three text editors. And the do_crypt works perfectly when I'm not using fuse. But when I try to decrypt in the fuse read function I get the right decrypted text but I also get those invalid characters. When I use the 'cat' terminal command the output does not include the invalid characters.
Here is a link to the full repo of code. https://github.com/latitude98/CU-CS3753-PA4