I'm using libgcrypt to encrypt and decrypt files. When I take in the proper amount of bytes using fread, I need to pad it with 16-n bytes in order for it to properly be encrypted by gcry_cipher_encrypt
. Upon decryption however, the null bytes/padding is still present. Is there any way to read and write in 16 byte blocks and still strip the padding at the end?
#include <stdio.h>
#include <gcrypt.h>
#define algo GCRY_CIPHER_AES128
#define mode GCRY_CIPHER_MODE_CBC
#define KEY_LENGTH 16
#define BLOCK_LENGTH 16
int main(){
char IV[16];
char *encBuffer = NULL;
FILE *in, *out, *reopen;
char *key = "A key goes here!";
gcry_cipher_hd_t handle;
int bufSize = 16, bytes;
memset(IV, 0, 16);
encBuffer = malloc(bufSize);
in = fopen("in.txt", "r");
out = fopen("out.txt", "w");
gcry_cipher_open(&handle, algo, mode, 0);
gcry_cipher_setkey(handle, key, KEY_LENGTH);
gcry_cipher_setiv(handle, IV, BLOCK_LENGTH);
while(1){
bytes = fread(encBuffer, 1, bufSize, in);
if (!bytes) break;
while(bytes < bufSize)
encBuffer[bytes++] = 0x0;
gcry_cipher_encrypt(handle, encBuffer, bufSize, NULL, 0);
bytes = fwrite(encBuffer, 1, bufSize, out);
}
gcry_cipher_close(handle);
fclose(in);
fclose(out);
gcry_cipher_open(&handle, algo, mode, 0);
gcry_cipher_setkey(handle, key, KEY_LENGTH);
gcry_cipher_setiv(handle, IV, BLOCK_LENGTH);
reopen = fopen("out.txt", "r");
out = fopen("decoded.txt", "w");
while(1){
bytes = fread(encBuffer, 1, bufSize, reopen);
if (!bytes) break;
gcry_cipher_decrypt(handle, encBuffer, bufSize, NULL, 0);
bytes = fwrite(encBuffer, 1, bufSize, out);
}
gcry_cipher_close(handle);
free(encBuffer);
return 0;
}
I was able to fix it by correctly storing the amount of padding and then checking for it later, suggested by zaph. I used PKCS#7 in order to determine how many bytes to write and of what type. I could've written NULL bytes, but there would've been no difference, so might as well stick to a standard.
#include <stdio.h>
#include <gcrypt.h>
#define algo GCRY_CIPHER_AES128
#define mode GCRY_CIPHER_MODE_CBC
#define KEY_LENGTH 16
#define BLOCK_LENGTH 16
int main(){
char IV[16], *encBuffer = NULL;
char *key = "A key goes here!";
int bufSize = 16, bytes, i=0, padding;
FILE *in, *out, *reopen;
gcry_cipher_hd_t handle;
memset(IV, 0, 16);
encBuffer = malloc(bufSize);
// Open in/out for reading and writing
in = fopen("in.txt", "r");
out = fopen("out.txt", "w");
// Set handle for encryption
gcry_cipher_open(&handle, algo, mode, 0);
gcry_cipher_setkey(handle, key, KEY_LENGTH);
gcry_cipher_setiv(handle, IV, BLOCK_LENGTH);
// Read from in, write encrypted to out
while(1){
bytes = fread(encBuffer, 1, bufSize, in);
if (!bytes) break;
// If fread grabbed less than 16 bytes, that's our final line
// Use the byte number for padding and pad N bytes of N
if ( bytes < BLOCK_LENGTH ){ padding = 16-bytes; }
while(bytes < bufSize)
encBuffer[bytes++] = padding;
gcry_cipher_encrypt(handle, encBuffer, bytes, NULL, 0);
bytes = fwrite(encBuffer, 1, bufSize, out);
}
// Close handle and i/o files
gcry_cipher_close(handle);
fclose(in);
fclose(out);
// Set handle for decryption
gcry_cipher_open(&handle, algo, mode, 0);
gcry_cipher_setkey(handle, key, KEY_LENGTH);
gcry_cipher_setiv(handle, IV, BLOCK_LENGTH);
// Reopen outfile, open decoded file
reopen = fopen("out.txt", "r");
out = fopen("decoded.txt", "w");
//Loop until EOF
while(1){
i=0;
bytes = fread(encBuffer, 1, bufSize, reopen);
if (!bytes) break;
gcry_cipher_decrypt(handle, encBuffer, bufSize, NULL, 0);
// Read each block and check for padding
while ( i++ < BLOCK_LENGTH ){
// If padding is found write 16-padding bytes
if ( encBuffer[i] == padding ){
bytes = fwrite(encBuffer, 1, (16-padding), out);
return 0;
}
}
// If padding isn't found, write the whole buffer
bytes = fwrite(encBuffer, 1, bufSize, out);
}
// Close the handle and free the buffer
gcry_cipher_close(handle);
free(encBuffer);
return 0;
}