1

I was playing with very simple encryption/decryption algorithm like this;

#include <stdio.h>
#include <stdlib.h>

#define BUFFESIZE 1024

int main(int argc, char *argv[]) {

    int keylen = 0;
    char *key = argv[1];
    char *buffer = NULL;
    size_t buffersize = 0;
    size_t nbytes = 0;
    size_t nread;
    int i = 0;
    while(*key++ != 0) keylen++;
    key = argv[1];

    do {
        buffersize+=BUFFESIZE;
        buffer = realloc(buffer, buffersize);
        nread = fread(buffer+nbytes, 1, BUFFESIZE, stdin);
        nbytes+=nread;
    } while (nread > 0);

    for(i=0; i<nbytes; i++) {
        putchar(buffer[i] ^ key[i % keylen]);
    }
    return 0;
}

Encyption key is the first command-line argument to the program. I expect that this should get me originial file when encrypted/decrypted with same key. However, I sometimes get only small amount of the file back if I encrypt/decrypt it. My guess is that algorithm adds EOF control character in the middle of file.

How can I get around this problem?

I compiled this using MinGW gcc 4.8.1 on windows XP. If you're interested, you can find a sample input file demonstrating the problem in the edit history of this question.

Community
  • 1
  • 1
yasar
  • 13,158
  • 28
  • 95
  • 160
  • Your code works fine for me (on Linux / GCC). What OS and compiler are you using? Also, it would help if you could paste in a short example of a file and a key that demonstrate the problem. – Ilmari Karonen Feb 28 '15 at 12:04
  • 2
    In any case, you might want to try [setting stdin and stdout to binary mode.](http://stackoverflow.com/questions/1598985/c-read-binary-stdin) – Ilmari Karonen Feb 28 '15 at 12:07
  • I'm guessing that the *ciphertext* has a `00` valued byte in it and that the rest isn't read. – Maarten Bodewes Feb 28 '15 at 12:41
  • @Maarten: Actually, nulls are not a problem for `fread()`. Apparently, however, on WIndows in text mode, the Ctrl-Z character (0x1A) is. – Ilmari Karonen Mar 01 '15 at 15:38
  • @IlmariKaronen Ugh, that's another entry in my Windows weirdness table inside my head. Growing and growing, hopefully I can put it into `{any folder at all}/NUL` someday. – Maarten Bodewes Mar 01 '15 at 15:44

1 Answers1

2

Well, your code works for me on Linux (compiled with GCC 4.8.2), even using your sample input and key. This suggests that the issue is specific to Windows — most likely, that it's caused by stdin and stdout being in text mode by default. (On Linux and other Unix-ish systems, there's usually no difference between text mode and binary mode, so such issues do not show up there.)

To fix it, you will need to set stdin and stdout to binary mode. The standard way of doing this, as of C99, would be:

freopen(NULL, "rb", stdin);
freopen(NULL, "wb", stdout);

but alas, according to the answers in the thread I linked to above, the Windows C library does not support this C99 feature, so you'll need to fall back on the non-standard _setmode() instead:

_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);

If you want to remain portable, you could always use some conditional code, e.g. like this (warning: not actually tested on Windows!):

#if __STDC_VERSION__ >= 199901L
  #define binmode(fh, w) freopen(NULL, ((w) ? "wb" : "rb"), (fh)) /* C99 */
#elif _MSC_VER >= 1200
  #include <io.h>
  #include <fcntl.h>
  #define binmode(fh, w) _setmode(_fileno(fh), _O_BINARY) /* MSVC 6.0+ */
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
  #define binmode(fh, w) /* Unix-ish, just do nothing */
#else
  #error Not sure how to define binmode() on this platform
#endif

binmode(stdin, 0);
binmode(stdout, 1);

Or, of course, you could just sidestep the whole issue by opening your own input and output files (in binary mode) instead of using stdin and stdout.

Community
  • 1
  • 1
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • 1
    I opened my own input and output files. I thought it was a simpler solution. And it works too. – yasar Mar 01 '15 at 15:24