1

I am trying to write a simple C program that encrypts a text file using the offset cipher.

Here is what I want the program to do:

  • Take a text file, read it character by character and after incrementing each character by some integer value (which increments the ASCII value of the character, resulting in some completely different characters to be obtained) overwrite the original text file such that it gets encrypted.

Here is my code: I am using an additional file named text.txt to store modified data and copy it back to the original file (named file.txt)

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

void encrypt(char *filename) {
    FILE *fp, *ft;
    int key = 1;
    char ch;
    fp = fopen(filename, "r+");
    ft = fopen("temp.txt", "w+");
    if (fp == NULL) {
        printf("Unable to open file");
        exit(1);
    }
    if (ft == NULL) {
        printf("Unable to generate encryption key");
        exit(2);
    }
    //modifying ASCII values and storing it in temp.txt
    while (1) {
        ch = fgetc(fp);
        if (ch == EOF)
            break;
        ch = ch + key; //offset
        fputc(ch, ft);
    }
    rewind(fp);
    rewind(ft);
    //copying temp to original file
    while (1) {
        ch = fgetc(ft);
        if (ch == EOF)
            break;
        fputc(ch, fp);
    }
    printf("The file has been encrypted successfully");
    fclose(fp);
    fclose(ft);
}

void decrypt(char *filename) {
    FILE *fp, *ft;
    char ch;
    fp = fopen(filename, "r+");
    ft = fopen("temp.txt", "w+");
    if (fp == NULL) {
        printf("Unable to open file");
        exit(1);
    }
    if (ft == NULL) {
        printf("Unable to access encryption key");
        exit(2);
    }
    //decrementing the chars by the same ASCII value to get back original text into temp.txt
    while (1) {
        ch = fgetc(fp);
        if (ch == EOF)
            break;
        ch = ch - 1;
        fputc(ch, ft);
    }
    rewind(fp);
    rewind(ft);
    //copying decrypted data to original file
    while (1) {
        ch = fgetc(ft);
        if (ch == EOF)
            break;
        fputc(ch, fp);
    }
    printf("File Decrypted Successfully");
}

int main(void) {
    int choice;
    char name[100], ch;
    FILE *fs, *ft;
    printf("To encrypt/decrypt a file: ");
    while (1) {
        printf("\nMENU");
        printf("\n1.Encrypt\n2.Decrypt\n");
        printf("Enter your choice: ");
        scanf("%d", &choice);
        fflush(stdin);
        switch (choice) {
          case 1:
            printf("Enter the name of the file to be encrypted: ");
            fgets(name, 99, stdin);
            strtok(name,"\n");
            encrypt(name);
            return 0;
            break;
          case 2:
            printf("Enter the name of the file to be decrypted: ");
            fgets(name, 99, stdin);
            strtok(name,"\n");
            decrypt(name);
            return 0;
            break;
        }
    }
}

But, the problem is that the encypt function works as expected while modifying the original file and storing it in temp.txt, but when it is copying the temp.txt file back into the original file, the last character is not being overwritten.

Below are some links to the output screenshots

Contents of the original file

Output when calling the encrypt function

Contents of the temp.txt file

Contents of the original file after copying(see how the trailing t is left unchanged)

What is wrong with my code? does it have to do something with the EOF of temp.txt or am I missing something obvious?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 1
    https://stackoverflow.com/questions/2979209/using-fflushstdin – William Pursell Jul 30 '22 at 12:58
  • 1
    Note that [`fgetc`](https://en.cppreference.com/w/c/io/fgetc) returns an **`int`**, which is rather important for that comparison against the `int` value `EOF`. – Some programmer dude Jul 30 '22 at 12:58
  • 1
    [**`int ch;`**](https://stackoverflow.com/a/35356684/918959) – Antti Haapala -- Слава Україні Jul 30 '22 at 12:59
  • `ch` must have been `int`, not `char`. – M. Nejat Aydin Jul 30 '22 at 13:13
  • I can't reproduce your issue. encrypting (ceaser cipher is not really "encryption" at all, though, this is just "encoding") followed by decrypting with your code works just fine and produces no changes in the file. – William Pursell Jul 30 '22 at 14:33
  • 1
    Note that error messages belong on stderr, and it is premature to print a message saying that the process has been successful before you've closed the file (and checked the return value of `fclose`). – William Pursell Jul 30 '22 at 14:34
  • Changing the **char** ch to **int** ch did fix the issue on the particular text that I posted in this question, after that I tried the program with several other texts having many lines and different characters, and I found that the same problem persists on the other test cases, and it is always the last one or two characters where the problem occurs. – Ayush Kumar Shukla Jul 31 '22 at 10:52
  • @WilliamPursell did you run this on a linux system? I indeed faced this issue on Windows, is this somehow system related? – Ayush Kumar Shukla Jul 31 '22 at 10:55

1 Answers1

0

I tried out your code and ran into an initial problem.

First, let me preface my problems and solution with the fact that I tested out your code on a Linux virtual machine.

The use of "fget" with the "stdin" handle did not work when I ran your code. It would skip right by that prompt without allowing me to enter a file name, say that no file name was found and end. So, to compensate for that, I switched out the fget input statements with "scanf" statements, as you were using that function earlier in your code.

        switch (choice)
        {
        case 1:
            printf("Enter the name of the file to be encrypted: ");
            scanf("%s", name);
            //strtok(name,"\n");
            encrypt(name);
            return 0;
            break;
        case 2:
            printf("Enter the name of the file to be decrypted: ");
            scanf("%s", name);
            //strtok(name,"\n");
            decrypt(name);
            return 0;
            break;
        }

When I made that change and entered in the name of my test file ("Notepad.txt"), the file encryption data in the temporary file matched what was stored in the input file that was updated.

Matching encrypted data

I don't know if you are testing this out on Windows system or a Linux system, but all I can say it worked for me. Others with more experience might chime in as to the difference in file opening, file puts, and so forth between the operating systems, but if you are curious and have access to a Linux machine (or virtual machine) you might try it out over there. And to eliminate the fget statements as a "suspect", you might try out the code switch I did when prompting for a file.

At the very least, food for thought.

NoDakker
  • 3,390
  • 1
  • 10
  • 11
  • I tried this out on a Windows machine, and changing the datatype of ch from **char** to **int** did fix the issue for some test cases. Since it worked fine for you on Linux, I guess that the behaviour of the **fgetc** function could be different depending upon the system but am not sure. – Ayush Kumar Shukla Jul 31 '22 at 11:01