Search code examples
cencryptionxor

XOR Encryption code produces wrong results


In the code blocks given below I am supposed to obtain an output like this:

  • Expected ciphertext: "'\r\u0006R\u0014\u0001\u001a\u0006\bR\a\u0006\u001c\u0012\rR\u0003\u001b\vE\t\a\b\u0004\0E\f\u0004\0\u0006S\u0011\v\u0017E\u0018\u0012\u001f\u001aR\u0001\u001b\u0014K"
  • Plain text: "The quick brown fox jumps over the lazy dog."
  • Secret: "secret"
  • My Output: 24 R

Original code address: https://www.programmingalgorithms.com/algorithm/xor-encryption/c/

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

char *XORCipher(char *data, char *key, int dataLen, int keyLen) {
  char *output = (char *)malloc(sizeof(char) * dataLen);

  for (int i = 0; i < dataLen; ++i) {
    output[i] = data[i] ^ key[i % keyLen];
  }

  return output;
}

int main(void) {

  char *text = "The quick brown fox jumps over the lazy dog.";
  char *key = "secret";
  int dataLen = strlen((char *)text);
  int keyLen = strlen((char *)key);

  char *cipherText = XORCipher(text, key, dataLen, keyLen);

  printf("%ld\n", strlen(cipherText));

  char *plainText = XORCipher(cipherText, key, dataLen, keyLen);
  printf("%s\n", cipherText);
  printf("%s\n", plainText);
}

Solution

  • So as said, there's nothing really wrong about your encryption code, you just can't print all of those bytes.

    Here's a slight rework that

    • moves the allocation outside the XORCipher function (so the caller is responsible for memory management)
    • adds an utility function to print byte values as well as the ASCII text
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    static void XORCipher(const char *data, const char *key, char *dest, int dataLen, int keyLen) {
      for (int i = 0; i < dataLen; ++i) {
        dest[i] = data[i] ^ key[i % keyLen];
      }
    }
    
    static void print_hex(const char *header, const unsigned char *data, int length) {
        int i = 0;
        while(i < length) {
            char asc_line[17] = {0};
            printf("%s(%04x): ", header, i);
            for(int j = 0; j < 16; i++, j++) {
                if(i < length) {
                    printf("%02x ", data[i]);
                    asc_line[j] = (data[i] >= 32 && data[i] <= 127 ? data[i] : '.');
                } else {
                    printf("   ");
                }
            }
            printf("| %-16s |\n", asc_line);
        }
        printf("%s\n----\n", data);
    }
    
    int main(void) {
    
      char *text = "The quick brown fox jumps over the lazy dog.";
      char *key = "secret";
      int dataLen = strlen((char *)text);
      int keyLen = strlen((char *)key);
      char *output = (char *)malloc(sizeof(char) * dataLen);
      print_hex("Original text", text, dataLen);
      XORCipher(text, key, output, dataLen, keyLen);
      print_hex("Ciphered text", output, dataLen);
      XORCipher(output, key, output, dataLen, keyLen);
      print_hex("Deciphered text", output, dataLen);
    }
    

    The output is

    Original text(0000): 54 68 65 20 71 75 69 63 6b 20 62 72 6f 77 6e 20 | The quick brown  |
    Original text(0010): 66 6f 78 20 6a 75 6d 70 73 20 6f 76 65 72 20 74 | fox jumps over t |
    Original text(0020): 68 65 20 6c 61 7a 79 20 64 6f 67 2e             | he lazy dog.     |
    The quick brown fox jumps over the lazy dog.
    ----
    Ciphered text(0000): 27 0d 06 52 14 01 1a 06 08 52 07 06 1c 12 0d 52 | '..R.....R.....R |
    Ciphered text(0010): 03 1b 0b 45 09 07 08 04 00 45 0c 04 00 06 53 11 | ...E.....E....S. |
    Ciphered text(0020): 0b 17 45 18 12 1f 1a 52 01 1b 14 4b             | ..E....R...K     |
    '
    RR
    RE  
    ----
    Deciphered text(0000): 54 68 65 20 71 75 69 63 6b 20 62 72 6f 77 6e 20 | The quick brown  |
    Deciphered text(0010): 66 6f 78 20 6a 75 6d 70 73 20 6f 76 65 72 20 74 | fox jumps over t |
    Deciphered text(0020): 68 65 20 6c 61 7a 79 20 64 6f 67 2e             | he lazy dog.     |
    The quick brown fox jumps over the lazy dog.
    ----
    

    (Note I'm deciphering the output back into output – that's fine in this instance since we know the cipher function works byte by byte.)