polslinux polslinux - 3 months ago 24
C Question

issue with encryption and decryption of a file in C with aes256-cbc using libgcrypt

prova is a plaintext file that contains hello i am a pc

encrypt:

FILE *fp = fopen("prova", "r+");
FILE *fpout = fopen("out", "w+");
while(!feof(fp)){
memset(plain_text, 0, sizeof(plain_text));
retval = fread(plain_text, 1, 16, fp);
txtLenght = sizeof(plain_text);
encBuffer = malloc(txtLenght);
algo = gcry_cipher_map_name(name);
gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_setkey(hd, key, keyLength);
gcry_cipher_setiv(hd, iniVector, blkLength);
gcry_cipher_encrypt(hd, encBuffer, txtLenght, plain_text, txtLenght);
fwrite(encBuffer, 1, 16, fpout);
}


decrypt:

FILE *fp = fopen("out", "r+");
FILE *fpout = fopen("origdec", "w+");
while(!feof(fp)){
memset(plain_text, 0, sizeof(plain_text));
retval = fread(plain_text, 1, 16, fp);
txtLenght = sizeof(plain_text);
encBuffer = malloc(txtLenght);
algo = gcry_cipher_map_name(name);
gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_setkey(hd, key, keyLength);
gcry_cipher_setiv(hd, iniVector, blkLength);
gcry_cipher_decrypt(hd, encBuffer, txtLenght, plain_text, txtLenght);
fwrite(encBuffer, 1, 16, fpout);
}


where:

char key[32] = {0x80};
char iniVector[16] = {0};
char plain_text[16];
char *encBuffer = NULL;


The problem: when i decipher the encrypted file, the file origdec contains the plain text plus some random useless and unreadable chars.

Answer

When you read your string,

fread(plain_text, 1, 16, fp);

you are probably getting "Hello I am a PC" (15 bytes) plus a return.

Then you encrypt 16 bytes, decrypt those 16 bytes, and still you do not have a string terminator, so that the printf writes extra stuff (or possibly coredumps).

You need to add a binary zero at the end of the string. Try:

fread(plain_text, 1, 16, fp);
plain_text[15] = 0x0;

and see whether this changes anything.

UPDATE

There are several errors in your code. For example you always reinitialize the cipher, and always reallocate encBuffer, leading to a memory leak. I have corrected some of the bugs; there remains the feature of the encrypted file being padded to 16 bytes. There are techniques to get rid of the padding; you may want to look at PKCS#7, for example.

I have initialized arbitrarily some constants, and employed in-place encrypt/decrypt (you are not limited to a bufSize of 16; but you will have to review the padding strategy).

#include <stdio.h>
#include <gcrypt.h>

int main()
{
    char iniVector[16];
    char *encBuffer = NULL;
    FILE *fp, *fpout;
    char *key       = "topolino e minni";
    gcry_cipher_hd_t hd;
    int     bufSize = 16, bytes, algo = GCRY_CIPHER_AES128, keyLength = 16, blkLength = 16;

    memset(iniVector, 0, 16);

    encBuffer = malloc(bufSize);

    fp = fopen("prova", "r");
    fpout = fopen("out", "w");

    gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
    gcry_cipher_setkey(hd, key, keyLength);
    gcry_cipher_setiv(hd, iniVector, blkLength);

    while(!feof(fp))
    {
        bytes = fread(encBuffer, 1, bufSize, fp);
        if (!bytes) break;
        while(bytes < bufSize)
            encBuffer[bytes++] = 0x0;
        gcry_cipher_encrypt(hd, encBuffer, bufSize, NULL, 0);
        bytes = fwrite(encBuffer, 1, bufSize, fpout);
    }
    gcry_cipher_close(hd);
    fclose(fp);
    fclose(fpout);

    // Decrypt. Same algo as before

    gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
    gcry_cipher_setkey(hd, key, keyLength);
    gcry_cipher_setiv(hd, iniVector, blkLength);

    fp = fopen("out", "r");
    fpout = fopen("origdec", "w");
    while(!feof(fp))
    {
        bytes = fread(encBuffer, 1, bufSize, fp);
        if (!bytes) break;
        gcry_cipher_decrypt(hd, encBuffer, bufSize, NULL, 0);
        bytes = fwrite(encBuffer, 1, bufSize, fpout);
    }
    gcry_cipher_close(hd);

    free(encBuffer); encBuffer = NULL;
    return 0;
}
Comments