1

I am implementing a Feistel cipher of block size 16 bits. I read from an input file into an integer (32bits), encrypt and write to output file.

unsigned int buf1, buf2;
FILE *fin = fopen("input", "r");
FILE *fout = fopen("output", "w");
while(!feof(fin)) {
    fread(&buf1, 4, 1, fin);
    buf2  = encrypt(buf1);
    fwrite(&buf2, 4, 1, fout);
}

The program is almost done. The only problem is that encryption followed by decryption is not the source file. They're almost same but the difference is only in the last bits. My question is what happens if the no of bytes in the file is not a multiple of 4. What will happen to the last call to fread()?

avmohan
  • 1,820
  • 3
  • 20
  • 39

2 Answers2

3

If the number of bytes in the file is not a multiple of 4, the last call to fread() will return 0.

size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream);
"The fread function returns the number of elements successfully read, which may be less than nmemb if a read error or end-of-file is encountered."

The result value of fread() should be used to detect an incomplete read and EOF. OP code, as is, will read once too often.

Also suggest using uint32_t instead of unsigned int for greater portability and checking `fwrite() results.

uint32_t buf1, buf2;
int cnt;
while((cnt = fread(&buf1, sizeof buf1, 1, fin)) == 1) {
  buf2  = encrypt(buf1);
  if (fwrite(&buf2, sizeof buf2, 1, fout) != 1) {
    Handle_WriteError();
  }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Suppose at the end, there are 3 bytes left. An incomplete read will be performed. So the 3 bytes will be read into higher 3 bytes or lower 3 bytes of integer? I need to read the last bytes and pad them to 4 bytes since the encrypt() operates on 4 bytes as a block. – avmohan Jan 20 '14 at 04:36
  • C11 7.21.8.1 2 "If a partial element is read, its value is indeterminate". If the file position was found `ftell()` before the failing `fread()`, code could `fseek()` to that point and try to read again 1 byte at a time. – chux - Reinstate Monica Jan 20 '14 at 04:37
  • 2
    @v3ga One could `cnt = fread(&buf1, 1, sizeof buf1, fin)` instead and use a `cnt == 4` as the happy path, 1 to 3 as a partial read with TBD padding code and 0 as EOF. – chux - Reinstate Monica Jan 20 '14 at 04:43
  • sry got it. to be determined :-/. Thanks. – avmohan Jan 20 '14 at 05:01
  • @v3ga Try `buf1 = 0; while((cnt = fread(&buf1, 1, sizeof buf1, fin)) > 0) { buf2 = encrypt(buf1); if (fwrite(&buf2, sizeof buf2, 1, fout) != 1) { Handle_WriteError(); } buf1 = 0; }` – chux - Reinstate Monica Jan 20 '14 at 05:02
0

You need to know the size of the file you are reading in advance (using stat() or equivalent), read the number of complete blocks available and then handle the residual bytes, if any, as a special case, perhaps by padding. If you don't want ciphertext expansion, then look at block stealing modes of operation, which are available for both ECB and CBC modes.

David G
  • 5,408
  • 1
  • 23
  • 19