导致 EOF 的简单 encryption/decryption 算法
Simple encryption/decryption algorithm causing EOF
我正在玩这样非常简单的 encryption/decryption 算法;
#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;
}
加密密钥是程序的第一个命令行参数。我希望当 encrypted/decrypted 使用相同的密钥时,这应该让我得到原始文件。但是,如果我 encrypt/decrypt 有时我只能得到少量的文件。我的猜测是算法在文件中间添加了 EOF 控制字符。
我怎样才能解决这个问题?
我在 windows XP 上使用 MinGW gcc 4.8.1 编译了这个。如果您有兴趣,可以在 the edit history of this question.
中找到演示该问题的示例输入文件
嗯,您的代码在 Linux(使用 GCC 4.8.2 编译)上对我有效,甚至使用您的示例输入和密钥。这表明该问题特定于 Windows — 最有可能的是,它是由默认情况下位于 text mode 中的 stdin 和 stdout 引起的。 (在 Linux 和其他 Unix-ish 系统上,文本模式和二进制模式之间通常没有区别,因此不会出现此类问题。)
要修复它,您需要 set stdin and stdout to binary mode. The standard way of doing this, as of C99,即:
freopen(NULL, "rb", stdin);
freopen(NULL, "wb", stdout);
但是,根据我上面链接的线程中的答案,Windows C 库 does not support this C99 feature, so you'll need to fall back on the non-standard _setmode()
相反:
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
如果你想保持可移植性,你总是可以使用一些条件代码,例如像这样(警告:未在 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);
或者,当然,您可以通过打开自己的输入和输出文件(以二进制模式)而不是使用 stdin
和 stdout
.
来回避整个问题
我正在玩这样非常简单的 encryption/decryption 算法;
#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;
}
加密密钥是程序的第一个命令行参数。我希望当 encrypted/decrypted 使用相同的密钥时,这应该让我得到原始文件。但是,如果我 encrypt/decrypt 有时我只能得到少量的文件。我的猜测是算法在文件中间添加了 EOF 控制字符。
我怎样才能解决这个问题?
我在 windows XP 上使用 MinGW gcc 4.8.1 编译了这个。如果您有兴趣,可以在 the edit history of this question.
中找到演示该问题的示例输入文件嗯,您的代码在 Linux(使用 GCC 4.8.2 编译)上对我有效,甚至使用您的示例输入和密钥。这表明该问题特定于 Windows — 最有可能的是,它是由默认情况下位于 text mode 中的 stdin 和 stdout 引起的。 (在 Linux 和其他 Unix-ish 系统上,文本模式和二进制模式之间通常没有区别,因此不会出现此类问题。)
要修复它,您需要 set stdin and stdout to binary mode. The standard way of doing this, as of C99,即:
freopen(NULL, "rb", stdin);
freopen(NULL, "wb", stdout);
但是,根据我上面链接的线程中的答案,Windows C 库 does not support this C99 feature, so you'll need to fall back on the non-standard _setmode()
相反:
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
如果你想保持可移植性,你总是可以使用一些条件代码,例如像这样(警告:未在 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);
或者,当然,您可以通过打开自己的输入和输出文件(以二进制模式)而不是使用 stdin
和 stdout
.