user1763100 user1763100 - 2 months ago 23
C Question

Blowfish CBC mode and Buffer Overrun in C

I am trying to use the OpenSSL library to encrypt and decrypt a string using the CBC block mode of Blowfish. For platform reasons this needs to be done in straight-C rather than C++. For some reason when the input string is longer than 8 characters (1 block), the size of the output increases dramatically.

For example: encrypting abcdefgh will generate an output 8 chars in length - all is good. However, encrypting abcdefgha will generate an output 699 chars long!

Am I doing something fundamentally wrong with this library? It was my understanding that the output from Blowfish should be the same size as the input. Can anyone explain what I'm doing wrong with this? If this is correct, how can I tell how big to create the output buffer as this code overruns it when the input is over 1 block.

Code sample below:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <openssl/blowfish.h>
const unsigned char* BLOWFISH_KEY = "TestKey!";
#define SIZE 8

unsigned char* blowfish_decrypt(unsigned char* in);
unsigned char* blowfish_encrypt(unsigned char* in);

int main(){

char* message = "abcdefgha";

char* encrypted = blowfish_encrypt(message);
printf("Encrypted: %s\n", encrypted);
printf("Size of encrypted: %d\n\n", strlen(encrypted));

char* decrypted = blowfish_decrypt(encrypted);
printf("Decrypt: %s\n", decrypted);
printf("Size of encrypted: %d\n\n", strlen(encrypted));
return 0;

}

unsigned char* blowfish_encrypt(unsigned char* in){

int i;
int SIZE_IN = strlen(in);
unsigned char *out = calloc(SIZE_IN+1, sizeof(char));

char ivec[8];
for(i=0; i<8; i++) ivec[i] = 'i';

BF_KEY *key = calloc(1, sizeof(BF_KEY));

/* set up a test key */
BF_set_key(key, SIZE, BLOWFISH_KEY );

BF_cbc_encrypt(in, out, strlen(in), key, ivec, BF_ENCRYPT);

printf("Size of out: %d\n", strlen(out));
printf("Size of in: %d\n", strlen(in));
return out;
}

unsigned char* blowfish_decrypt(unsigned char* in){

int i;
int SIZE_IN = strlen(in);
unsigned char *out = calloc(SIZE_IN+1, sizeof(char));

char ivec[8];
for(i=0; i<8; i++) ivec[i] = 'i';

BF_KEY *key = calloc(1, sizeof(BF_KEY));

/* set up a test key */
BF_set_key(key, SIZE, BLOWFISH_KEY );

BF_cbc_encrypt(in, out, strlen(in), key, ivec, BF_DECRYPT);

printf("Size of out: %d\n", strlen(out));
printf("Size of in: %d\n", strlen(in));
return out;
}

Answer

When your input string is encrypted, the resulting data is no longer a string that you could use strlen() to get its length. You could only treat the data as binary stream.

Since Blowfish is a block cipher, you have to ensure your input is a multiple of the the block size, and you have to take care of the padding if input length does not fit. The output length is the same as your input when you do the proper padding for your simple test.

You could use the higher level of EVP encrypt/decrypt functions http://linux.die.net/man/3/evp_encryptinit, padding is enable by default.

Comments