我创建了两个函数“encryptf”和“decrytpf”(用“f”命名以避免与预先存在的 libsodium 函数发生命名冲突。这些函数非常不言自明,它们使用提供的提供的加密和解密给定的输入字符串关键。
以下是加密方法。应该注意的是,“密钥”是一个简单的随机生成的 ANSI 字符字符串。
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;
}
以及解密功能:
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;
}
以下是我如何运行这些函数的基本示例。这不是我的确切代码,但充分说明了我如何使用这些函数而不暴露我的代码库:
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);
}
这确实会解密文件的内容,但还会在末尾附加以下奇怪的字符:
(我知道堆栈溢出不喜欢图像,但似乎我的键盘无法复制它们,或者无法显示它们,因为复制/粘贴它们没有任何作用。)
我确信删除这些字符很重要,因为我不想在加密/解密之前或之后留下任何痕迹或解密方式,或在没有密钥的情况下获取有关这些文件的任何信息。
我尝试删除 libsodium 提供的身份验证代码,因为我希望这可能是问题所在,但这样做似乎会破坏文件解密过程。
我不确定这是否重要,但我正在使用苹果 M2 芯片的 2023 款 MacBook Pro 上运行。
感谢大家提供的任何帮助!
对于所有可能遇到同样问题的人,我通过改变我使用的方式解决了它
fwrite
,来自:
fwrite(plaintext, 1, file_size, output);
到
fwrite(plaintext, 1, file_size - crypto_secretbox_MACBYTES, output);
考虑
crypto_secretbox_easy
添加的 MAC 身份验证标签。