Search code examples
cfileencryption

How to XOR a file buffer in C and output to a new file


Why does my output contain extra characters? Why is only the first line of every file via notepad++ being encrypted and not the entire file? Happy coding! P.S I have the Second Edition of C programming language by Kernighan and Ritchie

EDIT: This code is my code after I fixed it, the question's has been answered. Thank you guys!

Here is my source NEW code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define getchar() getc(stdin)
#define putchar() putc((c),stdout)
#define XOR_BYTE 0x9E

char * xorBuffer(char *buffer, long bufferSize){

    int i;
    for(i = 0;i <= bufferSize;i++){
        buffer[i] ^= XOR_BYTE;
    }
    return buffer;
}

int xorFile(char *fileIn, char * fileOut){

    FILE *fpi, *fpo;
    char *fileBuffer = NULL;

    fpi = fopen(fileIn,"rb");
    fpo = fopen(fileOut,"wb");

    if(NULL == fpi){
        printf("Error opening input file %s: %s\n", fileIn, strerror(errno));
        return 1;
    }
    if(NULL == fpo){
        printf("Error opening output file %s: %s\n", fileOut, strerror(errno));
        return 2;
    }

    fseek(fpi,0L,SEEK_END);
    long fileSize = ftell(fpi); 
    fileBuffer = malloc(sizeof(char)* (fileSize + 1));  
    fseek(fpi,0L,SEEK_SET);     
    size_t length = fread(fileBuffer, sizeof(char), fileSize,fpi);      
    fileBuffer[length];
    fileBuffer = (char *)xorBuffer(fileBuffer,fileSize);    
    int c;  
    for(c = 0;c < fileSize;c++){ 
        putc(((fileBuffer[c])),fpo);
    }

    fclose(fpi);
    fclose(fpo);
    free(fileBuffer);
    return 0;
}

int main(int argc, char*argv[]){
    if(argc == 3){
        if(xorFile(argv[1],argv[2]) == 0)
            printf("File encryption was successful.");
        else
            printf("An error occured.");
    }else{
        printf("usage --- xor [input file][output file]");
    }
}

Solution

  • Your prototype for XOR_FILE is incorrect: you should take 2 strings.

    There are more issues in your code:

    • you must learn to indent your code and use spaces wisely. Use the Kernighan and Ritchie style shown in the book.
    • you cannot reliably get the file size with fseek and ftell, it is not needed in general and you can implement a bufferized version with a fixed sized buffer anyway.
    • avoid overwriting the input file in your program. If you make a mistake, or if the program fails or is interrupted, the file contents may be corrupted or lost.
    • you do not need to null terminate the array into which you read the file, just iterate over all bytes, but stop at the size read: use for (i = 0; i < newLen; i++) otherwise you would output an extra byte when encrypting and one more when deciphering...
    • do not iterate until '\0' in XOR_BUFFER(char *FILE_BUFFER), pass the size and use it. Otherwise you will fail to encrypt binary files that contain null bytes.
    • you forget to close fpo with fclose(fpo);
    • do not redefine standard functions such as getchar() and putchar().
    • do not use uppercase letters for function names and/or variable names, but it is indeed common practice to use uppercase letters for macros.

    Here is a simplified version:

    #include <errno.h>
    #include <stdio.h>
    #include <string.h>
    
    #define XOR_BYTE   0x9E
                        
    int xor_file(const char *infile, const char *outfile) {
        FILE *fpi, *fpo;
        int c;
    
        if ((fpi = fopen(infile, "rb")) == NULL) {
            fprintf(stderr, "cannot open input file %s: %s\n", infile, strerror(errno));
            return 1;
        }
        if ((fpo = fopen(outfile, "wb")) == NULL) 
            fprintf(stderr, "cannot open output file %s: %s\n", outfile, strerror(errno));
            fclose(fpi);
            return 2;
        }
    
        while ((c = getc(fpi)) != EOF) {
            putc(c ^ XOR_BYTE, fpo);
        }
        fclose(fpi);
        fclose(fpo);
        return 0;
    }
    
    int main(int argc, char *argv[]) {
        int status;
    
        if (argc == 3) {
            status = xor_file(argv[1], argv[2]);
        } else {
            fprintf(stderr, "usage: xor_file input_file output_file\n");
            status = 3;
        }
        //getch();  // avoid the need for this by running your program in the terminal
        return status;
    }