If you have a good example of simply encrypting a file using openssl that is better than this one that I am having issues with I would be very grateful.
Up
Since you say the error seems to be coming at the decryption stage, I would look with suspicion on these lines:
if (EVP_DecryptUpdate (&ctx, outbuf, &olen, inbuff, n) != 1)
...
if (EVP_DecryptFinal (&ctx, outbuf + olen, &tlen) != 1)
...
How big is the memory allocated for outbuf
in relation to what the decryption functions will be putting in them? Are you sure outbuf + olen
is not going to take you past the end of the buffer?
The error is in the way the EVP_DecryptFinal and EVP_EncryptFinal are called. These functions should be called in the end of the for cycle, also the final part where to olen is added tlen and written again was duplicating output. Below is the final working version:
#include <openssl/blowfish.h>
#include <openssl/evp.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#define IP_SIZE 1024
#define OP_SIZE 1024 + EVP_MAX_BLOCK_LENGTH
unsigned char key[16];
unsigned char iv[8];
int
generate_key()
{
int i, fd;
if ((fd = open("/dev/random", O_RDONLY)) == -1)
perror("open error");
if ((read(fd, key, 16)) == -1)
perror("read key error");
if ((read(fd, iv, 8)) == -1)
perror("read iv error");
printf("128 bit key:\n");
for (i = 0; i < 16; i++)
printf("%4d ", key[i]);
printf("\nInitialization vector\n");
for (i = 0; i < 8; i++)
printf("%4d ", iv[i]);
printf("\n");
close(fd);
return 0;
}
int
do_decrypt(int infd, int outfd)
{
unsigned char *inbuff, *outbuf;
int olen=0, tlen=0, n=0;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit(&ctx, EVP_bf_cbc(), key, iv);
outbuf = (unsigned char *) malloc(sizeof(unsigned char) * OP_SIZE);
inbuff = (unsigned char *) malloc(sizeof(unsigned char) * IP_SIZE);
/* keep reading until a break */
for (;;) {
memset(inbuff, 0, IP_SIZE);
if ((n = read(infd, inbuff, IP_SIZE)) == -1) {
perror("read error");
break;
} else if (n == 0)
break;
memset(outbuf, 0, OP_SIZE);
if (EVP_DecryptUpdate(&ctx, outbuf, &olen, inbuff, n) != 1) {
printf("error in decrypt update\n");
return 0;
}
if ((n = write(outfd, outbuf, olen)) == -1)
perror("write error");
}
tlen=0;
if (EVP_DecryptFinal(&ctx, outbuf + olen, &tlen) != 1) {
perror("error in decrypt final");
return 0;
}
if ((n = write(outfd, outbuf+olen, tlen)) == -1)
perror("write error");
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}
int
do_encrypt(int infd, int outfd)
{
unsigned char *inbuff, *outbuf;
int olen=0, tlen=0, n=0;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit(&ctx, EVP_bf_cbc(), key, iv);
outbuf = (unsigned char *) malloc(sizeof(unsigned char) * OP_SIZE);
inbuff = (unsigned char *) malloc(sizeof(unsigned char) * IP_SIZE);
for (;;) {
memset(inbuff, 0, IP_SIZE);
if ((n = read(infd, inbuff, IP_SIZE)) == -1) {
perror("read error");
break;
} else if (n == 0)
break;
if (EVP_EncryptUpdate(&ctx, outbuf, &olen, inbuff, n) != 1) {
printf("error in encrypt update\n");
return 0;
}
if ((n = write(outfd, outbuf, olen)) == -1)
perror("write error");
}
tlen=0;
if (EVP_EncryptFinal(&ctx, outbuf + olen, &tlen) != 1) {
printf("error in encrypt final\n");
return 0;
}
if ((n = write(outfd, outbuf+olen, tlen)) == -1)
perror("write error");
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}
int
main(int argc, char *argv[])
{
int flags1 = 0, flags2 = 0, outfd, infd;
mode_t mode;
memset(key, 0, 16);
memset(iv, 0, 8);
memset(&mode, 0, sizeof(mode));
flags1 = flags1 | O_RDONLY;
flags2 = flags2 | O_RDONLY;
flags2 = flags2 | O_WRONLY;
flags2 = flags2 | O_CREAT;
mode = mode | S_IRUSR;
mode = mode | S_IWUSR;
generate_key();
if ((infd = open(argv[1], flags1, mode)) == -1)
perror("open input file error");
if ((outfd = open(argv[2], flags2, mode)) == -1)
perror("open output file error");
do_encrypt(infd, outfd);
close(infd);
fsync(outfd);
close(outfd);
if ((infd = open(argv[2], flags1, mode)) == -1)
perror("open output file error");
if ((outfd = open(argv[3], flags2, mode)) == -1)
perror("open output file error");
do_decrypt(infd, outfd);
close(infd);
fsync(infd);
close(outfd);
return 0;
}