'xor' is an operator keyword. I would not recommend creating a #define using the same name.
#define xor(x) ((((x) >= 0) && ((x) <= 255)) ? ((x) ^= KEY) : ((x) = 0))
(x) >= 0 will always return true too since you're using an unsigned type.
sizeof(char) will always be 1 too.
bptr = malloc(sizeof(unsigned char) * s);
You only need to malloc(s).
You have an unused parameter too:
const char *fn
Lastly, your chkret macro is convenient, but it does not guarantee memory is freed properly as it should in the case that files and memory are successfully closed and freed. return -1; happens before any of this is possible:
fclose(fp);
free(bptr);
In the case that these should be called.
Maybe something like this would be better:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define KEY 0x2E
#define SAFE_FREE(p) free(bptr); bptr = NULL;
#define chkgoto(func, var, retvar, label) \
if (!(var)) \
{ \
perror(func); \
retvar = -1; \
goto label; \
}
unsigned char *bptr;
size_t fsize(const char *fn);
int bpull(FILE *fp, unsigned char *b, size_t s);
int main(int argc, char *argv[])
{
char *fn = NULL;
FILE *fp = NULL;
int ret = 0, r;
size_t s, i;
if (argc != 2)
{
fprintf(stderr, "Usage: ./xcat <file>\n");
return -1;
}
fn = argv[1];
s = fsize(fn);
chkgoto("fsize", s, ret, end_label)
fp = fopen(fn, "rb");
chkgoto("fopen", fp, ret, end_label)
bptr = malloc(s);
chkgoto("malloc", bptr, ret, end_label)
r = bpull(fp, bptr, s);
chkgoto("bpull", r, ret, end_label)
for (i = 0; i < s; ++i)
bptr[i] ^= KEY;
fwrite(bptr, 1, s, stdout);
end_label:
if (fp) fclose(fp);
if (bptr) { SAFE_FREE(bptr) }
return ret;
}
size_t fsize(const char *fn)
{
struct stat st;
return (stat(fn, &st) == 0) ? st.st_size : 0;
}
int bpull(FILE *fp, unsigned char *b, size_t s)
{
return ((s - 1) == fread(b, 1, s, fp)) ? 0 : -1;
}
As a reminder too, if you consider the expansion of your macro, using a semi-colon after chkret() is not necessary, you're adding a null statement to your code.
I wouldn't recommend this for any kind of secure encryption though. This isn't even a cyclical xor, it's just a single one byte key xor.