I'm messing around with GnuTLS and I want to write a C program which encrypts/decrypts a file using the GnuTLS functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#define KEY_LENGTH 32
#define IV_LENGTH 16
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <input_file> <output_file> <password>\n", argv[0]);
return 1;
}
int ret;
const char *input_filename = argv[1];
const char *output_filename = argv[2];
gnutls_global_init();
gnutls_cipher_hd_t handle;
gnutls_cipher_algorithm_t cipher_alg = GNUTLS_CIPHER_AES_256_CBC;
const gnutls_datum_t key = { (void*)"ThisIsAStrongAESKey1234567890", 32 };
const gnutls_datum_t iv = { (void*)"RandomInitializationVector", 16 };
// Initialize the session and cipher handle
ret = gnutls_cipher_init(&handle, cipher_alg, &key, &iv);
if (ret < 0) {
fprintf(stderr, "Error initializing cipher: %s\n", gnutls_strerror(ret));
return 1;
}
// Open the input and output files
FILE *input_file = fopen(input_filename, "rb");
FILE *output_file = fopen(output_filename, "wb");
if (!input_file || !output_file) {
perror("Error opening files");
return 1;
}
// Read and encrypt the input file
unsigned char plaintext[4096];
unsigned char ciphertext[4096];
size_t read_bytes;
while ((read_bytes = fread(plaintext, 1, sizeof(plaintext), input_file)) > 0) {
ret = gnutls_cipher_encrypt2(handle, plaintext, read_bytes, ciphertext, sizeof(ciphertext));
if (ret < 0) {
fprintf(stderr, "Error encrypting: %s\n", gnutls_strerror(ret));
return 1;
}
fwrite(ciphertext, 1, read_bytes, output_file);
}
// Clean up
fclose(input_file);
fclose(output_file);
gnutls_cipher_deinit(handle);
gnutls_global_deinit();
return 0;
}
I've actually implemented only the encryption part, to see how is working, but it is not :) When I try to encrypt a .txt file, I've got the following output:
Error encrypting: The request is invalid.
It is possible that I'm missing something on initialising the cipher? Or is there anything else I should configure before using the gnutls_cipher_encrypt2() function?
I have the GnuTLS source code and I think that's where the error code is returned: lib/cipher_int.h:96
inline static int _gnutls_cipher_encrypt2(const cipher_hd_st *handle,
const void *text, size_t textlen,
void *ciphertext,
size_t ciphertextlen)
{
if (likely(handle != NULL && handle->handle != NULL)) {
if (handle->encrypt == NULL) {
return (GNUTLS_E_INVALID_REQUEST);
}
return handle->encrypt(handle->handle, text, textlen,
ciphertext, ciphertextlen);
}
return 0;
}
Should I change handle->encrypt somehow?
I believe that the error is caused by the fact that the size of your plaintext file is not a multiple of the AES block size (16 bytes).
int gnutls_cipher_encrypt2 (gnutls_cipher_hd_t handle, const void * ptext, size_t ptext_len, void * ctext, size_t ctext_len)
"This function will encrypt the given data using the algorithm specified by the context. For block ciphers the ptext_len MUST be a multiple of the block size. For the supported ciphers the encrypted data length will equal the plaintext size." -- https://www.gnutls.org/manual/html_node/Cryptographic-API.html#gnutls_005fcipher_005finit
You should pad your plaintext with the 10^* padding. This is also mentioned by the NIST. See Appendix A: Padding from the NIST Special Publication 800-38A 2001. https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf