Search code examples
calgorithmblowfish

Reading in 64 byte chunks from a file in C


I can't seem to wrap my head around this concept of reading in 64byte chunks, then using the blowfish,

BF_cfb64_encrypt(source, dest, sizeof(source), &bf_key, iv, &enc, BF_DECRYPT) 

function to encrypt? it. I know how to use the BF function, but reading in 64 bytes, from say a 4096 byte file is my confusion. Any tips or suggestions would be greatly appreciated. My understanding is that 1 char is a byte, so does that mean I simply keep a count and when char count is 8 then that means I have read 64 bytes, hence encrypt, then write to file, and repeat until the entire file is parsed?


Solution

  • First, familiarity with your stream cipher is probably warranted. Blowfish encrypts/decrypts using a block size of 64 bits; not bytes. So long as you understand the 64 "bytes" you're referring to is your requirement and not Blowfishes, and that Blowfish only requires 8-byte blocks.

    That said, a loop passing over a file with a size that is a multiple of the algorithm block size, extracting decrypted data one 64 byte frame at a time is certainly doable.

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <openssl/blowfish.h>
    
    
    int main(int argc, char *argv[])
    {
        if (argc < 2)
            return EXIT_FAILURE;
    
        FILE * fp = fopen(argv[1], "rb");
        if (fp == NULL)
        {
            perror(argv[1]);
            return EXIT_FAILURE;
        }
    
        // your key bytes would be here (obviously).
        unsigned char key[16] = "1234567890123456";
        int key_len = sizeof(key)-1;
    
        // setup the key schedule.
        BF_KEY bf_key;
        BF_set_key(&bf_key, key_len, key);
    
        // and setup the initialization vector. normally the IV is
        //  randomly generated when encrypting, then stored as the
        //  lead 8 bytes of ciphertext output. this assumes you're
        //  iv is static (all zeros) similar to SSH
        unsigned char iv[8] = {0};
        int n = 0;
    
        // finally, begin reading the data in chunks of 64 bytes
        //  sending it through the blowfish algorithm
        unsigned char source[64];
        unsigned char dest[64];
        while (fread(source, sizeof(source), 1, fp) == 1)
        {
            BF_cfb64_encrypt(source, dest, sizeof(dest), &bf_key, iv, &n, BF_DECRYPT);
    
            // do something with your dest[] plaintext block
        }
        fclose(fp);
    
        return 0;
    }
    

    That sample is fairly trivial, but it brings up some things about symmetric block algorithms and padding that you may not be considering (or perhaps you have, and it simply has nothing to do with this question).

    Symmetric block algorithms like Blowfish operate on a block size. In the case of Blowfish that block size is 64 bits (8 bytes). This means that the encryption/decryption operation always happens in 64-bit-sized chunks. If if you were using the lower level openssl apis you would have to encrypt (and decrypt) the data in blocks no larger than that. The higher-level APIs (such as BF_cfb64_encrypt) are designed to allow "stream mode" meaning you can submit your data in larger chunks, so long as they're sized to be a multiple of the block size. and you retain the iv and n values between chained successive calls to the API.

    Finally, I started writing this rather long diatribe about symmetric block algorithms and padding modes, but realized this isn't really appropriate to this question, so I can only suggest you research into them. I've a suspicion you'll need to at some point.