What I am trying to do: Write a program in C that opens a file of arbitrary size and reads its contents. Once The contents are read it will encrypt them in AES 256 CBC and save the ciphertext to a file called ciphertext. Once this is saved it will close both files. Then will open the cipher text from the file that was just saved and decrypt the cipher text and save it to a file called decrypted.
My Problem: It seems to never decrypt my cipher text. I get garbage, I have no idea what I am doing wrong. Please help.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
void encrypt(FILE *ifp, FILE *ofp)
{
//Get file size
fseek(ifp, 0L, SEEK_END);
int fsize = ftell(ifp);
//set back to normal
fseek(ifp, 0L, SEEK_SET);
int outLen1 = 0; int outLen2 = 0;
unsigned char *indata = malloc(fsize);
unsigned char *outdata = malloc(fsize*2);
unsigned char ckey[] = "thiskeyisverybad";
unsigned char ivec[] = "dontusethisinput";
//Read File
fread(indata,sizeof(char),fsize, ifp);//Read Entire File
//Set up encryption
EVP_CIPHER_CTX ctx;
EVP_EncryptInit(&ctx,EVP_aes_256_cbc(),ckey,ivec);
EVP_EncryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
EVP_EncryptFinal(&ctx,outdata,&outLen2);
fwrite(outdata,sizeof(char),fsize,ofp);
}
void decrypt(FILE *ifp, FILE *ofp)
{
//Get file size
fseek(ifp, 0L, SEEK_END);
int fsize = ftell(ifp);
//set back to normal
fseek(ifp, 0L, SEEK_SET);
int outLen1 = 0; int outLen2 = 0;
unsigned char *indata = malloc(fsize);
unsigned char *outdata = malloc(fsize*2);
unsigned char ckey[] = "thiskeyisverybad";
unsigned char ivec[] = "dontusethisinput";
//Read File
fread(indata,sizeof(char),fsize, ifp);//Read Entire File
//setup decryption
EVP_CIPHER_CTX ctx;
EVP_DecryptInit(&ctx,EVP_aes_256_cbc(),ckey,ivec);
EVP_DecryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
EVP_DecryptFinal(&ctx,outdata,&outLen2);
fwrite(outdata,sizeof(char),fsize,ofp);
}
int main(int argc, char *argv[])
{
FILE *fIN, *fOUT;
fIN = fopen("plain.txt", "rb");//File to be encrypted; plain text
fOUT = fopen("cyphertext.txt", "wb");//File to be written; cipher text
encrypt(fIN, fOUT);
fclose(fIN);
fclose(fOUT);
//Decrypt file now
fIN = fopen("cyphertext.txt", "rb");//File to be written; cipher text
fOUT = fopen("decrypted.txt", "wb");//File to be written; cipher text
decrypt(fIN,fOUT);
fclose(fIN);
fclose(fOUT);
return 0;
}
Note: there may be some misspellings. EDIT: Seems Like I made a mistake with the key and IV, both of which are 128 bit and I am trying to use the 256 bit CBC. This was my problem, seems to work once I changed it to
EVP_aes_128_cbc()
That's right - the EVP_* functions are "envelope encryption".
CBC (short for cipher-block chaining) is a AES block cipher mode that trumps the ECB mode in hiding away patterns in the plaintext. CBC mode achieves this by XOR-ing the first plaintext block (B1) with an initialization vector before encrypting it.
AES 256 is virtually impenetrable using brute-force methods. While a 56-bit DES key can be cracked in less than a day, AES would take billions of years to break using current computing technology. Hackers would be foolish to even attempt this type of attack. Nevertheless, no encryption system is entirely secure.
AES-GCM is a more secure cipher than AES-CBC, because AES-CBC, operates by XOR'ing (eXclusive OR) each block with the previous block and cannot be written in parallel. This affects performance due to the complex mathematics involved requiring serial encryption.
Here is my version of your code. Naturally I like it better, but I offer it just as an alternative. Note the complete absence of error checking: real code would have it.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/**
* Encrypt or decrypt, depending on flag 'should_encrypt'
*/
void en_de_crypt(int should_encrypt, FILE *ifp, FILE *ofp, unsigned char *ckey, unsigned char *ivec) {
const unsigned BUFSIZE=4096;
unsigned char *read_buf = malloc(BUFSIZE);
unsigned char *cipher_buf;
unsigned blocksize;
int out_len;
EVP_CIPHER_CTX ctx;
EVP_CipherInit(&ctx, EVP_aes_256_cbc(), ckey, ivec, should_encrypt);
blocksize = EVP_CIPHER_CTX_block_size(&ctx);
cipher_buf = malloc(BUFSIZE + blocksize);
while (1) {
// Read in data in blocks until EOF. Update the ciphering with each read.
int numRead = fread(read_buf, sizeof(unsigned char), BUFSIZE, ifp);
EVP_CipherUpdate(&ctx, cipher_buf, &out_len, read_buf, numRead);
fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
if (numRead < BUFSIZE) { // EOF
break;
}
}
// Now cipher the final block and write it out.
EVP_CipherFinal(&ctx, cipher_buf, &out_len);
fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
// Free memory
free(cipher_buf);
free(read_buf);
}
int main(int argc, char *argv[]) {
unsigned char ckey[] = "thiskeyisverybad";
unsigned char ivec[] = "dontusethisinput";
FILE *fIN, *fOUT;
if (argc != 2) {
printf("Usage: <executable> /path/to/file/exe");
return -1;
}
// First encrypt the file
fIN = fopen("plain.txt", "rb"); //File to be encrypted; plain text
fOUT = fopen("cyphertext.txt", "wb"); //File to be written; cipher text
en_de_crypt(TRUE, fIN, fOUT, ckey, ivec);
fclose(fIN);
fclose(fOUT);
//Decrypt file now
fIN = fopen("cyphertext.txt", "rb"); //File to be read; cipher text
fOUT = fopen("decrypted.txt", "wb"); //File to be written; cipher text
en_de_crypt(FALSE, fIN, fOUT, ckey, ivec);
fclose(fIN);
fclose(fOUT);
return 0;
}
This code works, if anyone has some suggestions as to how it would be cleaner or more efficient please drop a comment.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
void encrypt(FILE *ifp, FILE *ofp)
{
//Get file size
fseek(ifp, 0L, SEEK_END);
int fsize = ftell(ifp);
//set back to normal
fseek(ifp, 0L, SEEK_SET);
int outLen1 = 0; int outLen2 = 0;
unsigned char *indata = malloc(fsize);
unsigned char *outdata = malloc(fsize*2);
unsigned char ckey[] = "thiskeyisverybad";
unsigned char ivec[] = "dontusethisinput";
//Read File
fread(indata,sizeof(char),fsize, ifp);//Read Entire File
//Set up encryption
EVP_CIPHER_CTX ctx;
EVP_EncryptInit(&ctx,EVP_aes_128_cbc(),ckey,ivec);
EVP_EncryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
EVP_EncryptFinal(&ctx,outdata + outLen1,&outLen2);
fwrite(outdata,sizeof(char),outLen1 + outLen2,ofp);
}
void decrypt(FILE *ifp, FILE *ofp)
{
//Get file size
fseek(ifp, 0L, SEEK_END);
int fsize = ftell(ifp);
//set back to normal
fseek(ifp, 0L, SEEK_SET);
int outLen1 = 0; int outLen2 = 0;
unsigned char *indata = malloc(fsize);
unsigned char *outdata = malloc(fsize);
unsigned char ckey[] = "thiskeyisverybad";
unsigned char ivec[] = "dontusethisinput";
//Read File
fread(indata,sizeof(char),fsize, ifp);//Read Entire File
//setup decryption
EVP_CIPHER_CTX ctx;
EVP_DecryptInit(&ctx,EVP_aes_128_cbc(),ckey,ivec);
EVP_DecryptUpdate(&ctx,outdata,&outLen1,indata,fsize);
EVP_DecryptFinal(&ctx,outdata + outLen1,&outLen2);
fwrite(outdata,sizeof(char),outLen1 + outLen2,ofp);
}
int main(int argc, char *argv[])
{
if(argc != 2){
printf("Usage: <executable> /path/to/file/exe");
return -1;
}
FILE *fIN, *fOUT;
fIN = fopen("plain.txt", "rb");//File to be encrypted; plain text
fOUT = fopen("cyphertext.txt", "wb");//File to be written; cipher text
encrypt(fIN, fOUT);
fclose(fIN);
fclose(fOUT);
//Decrypt file now
fIN = fopen("cyphertext.txt", "rb");//File to be written; cipher text
fOUT = fopen("decrypted.txt", "wb");//File to be written; cipher text
decrypt(fIN,fOUT);
fclose(fIN);
fclose(fOUT);
return 0;
}
Also According to this post the EVP api will handle an arbitrary sized input
AES Encryption- large files
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With