I have created two functions 'encryptf', and 'decrytpf' (named with 'f' to avoid naming conflict with pre-existing libsodium functions. These functions are pretty self explanatory, they encrypt, and decrypt a given input string using a provided key.
The following is the encryption method. It should be noted that the 'key' is simple a randomly generated string of ANSI characters.
int encryptf(const char *input_file, const char *output_file, const unsigned char *key) {
if (sodium_init() < 0) {
printf("Error initializing\n");
return 1;
}
// Get input and output files and ensure read/write, creation if needed.
FILE *input = fopen(input_file, "r");
FILE *output = fopen(output_file, "ab+");
if (!input || !output) {
printf("Error opening files to encrypt\n");
return 1;
}
// Get file size
fseek(input, 0, SEEK_END);
size_t file_size = ftell(input);
fseek(input, 0, SEEK_SET);
// Allocate memory for plaintext and ciphertext
unsigned char *plaintext = (unsigned char *) malloc(file_size);
unsigned char *ciphertext = (unsigned char *) malloc(file_size + crypto_secretbox_MACBYTES);
// Create nonce char array, and populate it with secure randombytes from libsodium library
unsigned char nonce[crypto_secretbox_NONCEBYTES];
randombytes(nonce, sizeof(nonce));
// Read plaintext from file
fread(plaintext, 1, file_size, input);
// Create 'mac' array to get rid of authentication tag.
unsigned char mac[crypto_secretbox_NONCEBYTES];
// Encrypt plaintext
crypto_secretbox_easy(ciphertext, plaintext, file_size, nonce, key);
// Write nonce and ciphertext to output file
fwrite(nonce, 1, sizeof(nonce), output);
fwrite(ciphertext, 1, file_size + crypto_secretbox_MACBYTES, output);
// Cleanup
fclose(input);
fclose(output);
free(plaintext);
free(ciphertext);
return 0;
}
And the decryption function:
int decryptf(const char *input_file, const char *output_file, const unsigned char *key) {
if (sodium_init() < 0) {
printf("Error initializing Libsodium\n");
return 1;
}
FILE *input = fopen(input_file, "rb");
FILE *output = fopen(output_file, "wb");
if (!input || !output) {
printf("Error opening files to decrypt\n");
return 1;
}
// Read nonce from file
unsigned char nonce[crypto_secretbox_NONCEBYTES];
fread(nonce, 1, sizeof(nonce), input);
// Get file size excluding nonce
fseek(input, 0, SEEK_END);
size_t file_size = ftell(input) - crypto_secretbox_NONCEBYTES;
fseek(input, crypto_secretbox_NONCEBYTES, SEEK_SET);
// Allocate memory for ciphertext and plaintext
unsigned char *ciphertext = (unsigned char *) malloc(file_size);
unsigned char *plaintext = (unsigned char *) malloc(file_size);
// Read ciphertext from file
fread(ciphertext, 1, file_size, input);
// Decrypt ciphertext
if (crypto_secretbox_open_easy(plaintext, ciphertext, file_size, nonce, key) != 0) {
printf("Error decrypting %s\n", input_file);
return 1;
}
// Write plaintext to output file
fwrite(plaintext, 1, file_size, output);
// Cleanup
fclose(input);
fclose(output);
free(ciphertext);
free(plaintext);
return 0;
}
What follows is a basic example of how I am running these functions. This is not my exact code, but is an ample representation of how I am using these functions without exposing my codebase:
int main(void) {
FILE *f1 = fopen("tests/file.txt", "ab+");
if (!f1 || !f2) {
printf("Failed create test files.\n");
exit(EXIT_SUCCESS);
}
fprintf(f1, "HELLO\n\nworld!\n..\n\thello\n../14hf\n1");
fclose(f1);
char *key = rand_string(32);
encryptf("tests/file.txt", "tests/file_enc.txt", key);
printf("File encrypted.\n");
decryptf("tests/file_enc.txt", "tests/file.txt", fkey);
}
This does decrypt the contents of the file, but also appends the following strange characters to the end:
(I am aware stack overflow is not fond of images, but it seems as though my keyboard cannot copy them, or cannot display them, as copy/pasting them does nothing.)
I am sure it's important that these characters get removed, as I do not want to be leaving any trace, or way to decrypt, or gain any information about these files without the key, before or after encryption/decryption.
I have tried removing the authentication code provided by libsodium, as I was hoping that could be the issue, but it seems as though doing so ruins the file decryption process.
I'm not sure if it will be important, but I am running on a 2023 MacBook Pro with apple's M2 chip.
Thank you all for any help you can provide!
To all those who might run into this same issue, I solved it by changing the way I used fwrite
, from:
fwrite(plaintext, 1, file_size, output);
to
fwrite(plaintext, 1, file_size - crypto_secretbox_MACBYTES, output);
To account for the MAC authentication tag that crypto_secretbox_easy
adds.