I'm writing some custom encryption code in Java for my server. The only problem is that in my encryption I'm using XOR. The data gets encrypted fine, but when I decrypt it doesn't decrypt correctly. I am not sure what is cuasing this problem.

Here is my code that I have so far:

// Transform (encrypt) data.
public long[] encryptData(long[] data) {
    int dataSize = data.length;
    long[] encryptedBytes = new long[dataSize];
    long dataByte = 0;
    int passwordIndex;

    // Encrypt the data with the first 4 sets.
    for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
        dataByte = data[dataIndex];

        for(int primeOrderIndex = 0; primeOrderIndex < 4; primeOrderIndex++) {
            for(int primeSetIndex = 0; primeSetIndex < 256; primeSetIndex++) {
                dataByte += this.primes[this.orderOfSets[primeOrderIndex]][primeSetIndex];
            }
        }

        encryptedBytes[dataIndex] = dataByte;
    }

    // Encrypt the data with the password.
    passwordIndex = 0;
    for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
        dataByte = encryptedBytes[dataIndex];

        if(passwordIndex == this.password.length()) {
            passwordIndex = 0;
        }

        dataByte = dataByte ^ (int)this.password.charAt(passwordIndex);

        encryptedBytes[dataIndex] = dataByte;
    }

    // Encrypt the data with the last 4 sets.
    for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
        dataByte = data[dataIndex];

        for(int primeOrderIndex = 4; primeOrderIndex < 8; primeOrderIndex++) {
            for(int primeSetIndex = 0; primeSetIndex < 256; primeSetIndex++) {
                dataByte += this.primes[this.orderOfSets[primeOrderIndex]][primeSetIndex];
            }
        }

        encryptedBytes[dataIndex] = dataByte;
    }

    return encryptedBytes;
}

// Decrypts the data.
public long[] decryptData(long[] encryptedData) {
    long[] decryptedBytes = new long[encryptedData.length];
    int dataSize = encryptedData.length;
    long dataByte;
    int passwordIndex;

    // Decrypt the data with the last 4 sets.
    for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
        dataByte = encryptedData[dataIndex];

        for(int primeOrderIndex = 7; primeOrderIndex >= 4; primeOrderIndex--) {
            for(int primeSetIndex = 255; primeSetIndex >= 0; primeSetIndex--) {
                dataByte -= this.primes[this.orderOfSets[primeOrderIndex]][primeSetIndex];
            }
        }

        decryptedBytes[dataIndex] = dataByte;
    }

    // Decrypt the data with the password.
    passwordIndex = 0;
    for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
        dataByte = decryptedBytes[dataIndex];

        if(passwordIndex == this.password.length()) {
            passwordIndex = 0;
        }

        dataByte = dataByte ^ (int)this.password.charAt(passwordIndex);

        decryptedBytes[dataIndex] = dataByte;
    }

    // Decrypt the data with the first 4 prime sets.
    for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
        dataByte = encryptedData[dataIndex];

        for(int primeOrderIndex = 3; primeOrderIndex >= 0; primeOrderIndex--) {
            for(int primeSetIndex = 255; primeSetIndex >= 0; primeSetIndex--) {
                dataByte -= this.primes[this.orderOfSets[primeOrderIndex]][primeSetIndex];
            }
        }

        decryptedBytes[dataIndex] = dataByte;
    }

    return decryptedBytes; 
}

And here is some sample output from the program:

Original: 104 101 108 108 111 
Encrypted: 38358030 38358027 38358034 38358034 38358037 
Decrypted: 32656297 32656294 32656301 32656301 32656304

Edited 1 Year Ago by CodeWarrior14

XOR'g with what? A key? If you used a key to XOR your data, then using the same key in the same order to XOR the encrypted data should result in the original plain text. This is cryptography 0.001. And what is the cruft about primes? Describe your algorithm and not the code.

Can you please provide the class you generated the output with? There are some things missing like the primes list in the code you gave. Thank you.

To answer the question in the title, "What is the inverse of XOR?". The answer is, XOR.

If you do this:
0xE1 XOR 0xA5

You will get:
0x44

And then you do this:
0x44 XOR 0xA5

To get this again:
0xE1

Hope I helped :)

Edited 1 Year Ago by krieg

Well thats what I also thought, but it doesn't quite work this way. I don't know why.

Herese the entire code:

public class CommandEncryption {
    private String password;
    private int[][] primes;
    private int[] orderOfSets;

    // Generates the prime numbers.
    public void generatePrimeNumbers() {
        int number = 1;
        int i = 0;
        primes = new int[8][256];

        // Generate primes for the first set.
        while (i < 256) {
            number++;
            if(isPrime(number)) {
                primes[0][i] = number;
                i++;
            }
        }

        // Generate primes for the second set.
        i = 0;
        while (i < 256) {
            number += 2;
            if(isPrime(number)) {
                primes[1][i] = number;
                i++;
            }
        }

        // Generate primes for the third set.
        i = 0;
         while (i < 256) {
            number += 3;
            if(isPrime(number)) {
                primes[2][i] = number;
                i++;
            }
        }

        // Generate primes for the fourth set.
        i = 0;
         while (i < 256) {
            number += (4 * 2);
            if(isPrime(number)) {
                primes[3][i] = number;
                i++;
            }
        }

        // Generate primes for the fith set.
        i = 0;
         while (i < 256) {
            number += 5;
            if(isPrime(number)) {
                primes[4][i] = number;
                i++;
            }
        }

        // Generate primes for the sixth set.
        i = 0;
         while (i < 256) {
            number += 6;
            if(isPrime(number)) {
                primes[5][i] = number;
                i++;
            }
        }

        // Generate primes for the seventh set.
        i = 0;
         while (i < 256) {
            number += 7;
            if(isPrime(number)) {
                primes[6][i] = number;
                i++;
            }
        }

        // Generate primes for the eigth set.
        i = 0;
         while (i < 256) {
            number += 8;
            if(isPrime(number)) {
                primes[7][i] = number;
                i++;
            }
        }
    }

    // Check if a number is prime.
    private boolean isPrime(long number) {
        boolean flag = true;

        if(number == 2) {
            return true;
        }
        if(number < 2) {
            return false;
        }

        for(long i = 2; i < number; i++) {
            if((number % i) == 0) {
                return false;
            } 
        }

        return flag;
    }

    // Transform (encrypt) data.
    public long[] encryptData(long[] data) {
        int dataSize = data.length;
        long[] encryptedBytes = new long[dataSize];
        long dataByte = 0;

        // Encrypt the data with the first 4 sets.
        for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
            dataByte = data[dataIndex];

            for(int primeOrderIndex = 0; primeOrderIndex < 4; primeOrderIndex++) {
                for(int primeSetIndex = 0; primeSetIndex < 256; primeSetIndex++) {
                    dataByte += this.primes[this.orderOfSets[primeOrderIndex]][primeSetIndex];
                }
            }

            encryptedBytes[dataIndex] = dataByte;
        }

        // Encrypt the data with the password.
       for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
            dataByte = encryptedBytes[dataIndex];

            for(int passwordIndex = 0; passwordIndex < this.password.length(); passwordIndex++) {
                dataByte = dataByte ^ (int)this.password.charAt(passwordIndex);
            }      
            encryptedBytes[dataIndex] = dataByte;
        }

        // Encrypt the data with the last 4 sets.
        for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
            dataByte = encryptedBytes[dataIndex];

            for(int primeOrderIndex = 4; primeOrderIndex < 8; primeOrderIndex++) {
                for(int primeSetIndex = 0; primeSetIndex < 256; primeSetIndex++) {
                    dataByte += this.primes[this.orderOfSets[primeOrderIndex]][primeSetIndex];
                }
            }

            encryptedBytes[dataIndex] = dataByte;
        }

        return encryptedBytes;
    }

    // Decrypts the data.
    public long[] decryptData(long[] encryptedData) {
        long[] decryptedBytes = new long[encryptedData.length];
        int dataSize = encryptedData.length;
        long dataByte = 0;

        // Decrypt the data with the first 4 sets.
        for(int dataIndex = dataSize - 1; dataIndex >= 0; dataIndex--) {
            dataByte = encryptedData[dataIndex];

            for(int primeOrderIndex = 3; primeOrderIndex >= 0; primeOrderIndex--) {
                for(int primeSetIndex = 255; primeSetIndex >= 0; primeSetIndex--) {
                    dataByte -= this.primes[this.orderOfSets[primeOrderIndex]][primeSetIndex];
                }
            }

            decryptedBytes[dataIndex] = dataByte;
        }

        // Decrypt the data with the password.
        for(int dataIndex = 0; dataIndex < dataSize; dataIndex++) {
            dataByte = decryptedBytes[dataIndex];

            for(int passwordIndex = 0; passwordIndex < this.password.length(); passwordIndex++) {
                dataByte = dataByte ^ (int)this.password.charAt(passwordIndex);
            }

            decryptedBytes[dataIndex] = dataByte;
        }

        // Decrypt the data with the last 4 sets.
        for(int dataIndex = dataSize - 1; dataIndex >= 0; dataIndex--) {
            dataByte = decryptedBytes[dataIndex];

            for(int primeOrderIndex = 7; primeOrderIndex >= 4; primeOrderIndex--) {
                for(int primeSetIndex = 255; primeSetIndex >= 0; primeSetIndex--) {
                    dataByte -= this.primes[this.orderOfSets[primeOrderIndex]][primeSetIndex];
                }
            }
            decryptedBytes[dataIndex] = dataByte;
        }

        return decryptedBytes; 
    }

    // Convert a string to long.
   public long[] convertStringToLong(String line) {
       long[] data = new long[line.length()];

       for(int i = 0; i < line.length(); i++) {
           data[i] = Long.valueOf(line.charAt(i));
       }

       return data;
   }

    // Initialize the encryption class.
    public CommandEncryption(String password, String orderOfSets) {
        this.password = password;

        this.orderOfSets = new int[8];
        for(int i = 0; i < 8; i++) {
            this.orderOfSets[i] = (int)orderOfSets.charAt(i) - 48;
        }

        generatePrimeNumbers();        
    }
}

The way that the algorithm works:
1) There are 7 arrays of 256 prime numbers generated and are stored in the private int[][] primes; variable.
These primes will be the key.
2) There is also a password that will be used as part of the key.
3) The message is truned into an array of long.
4) This message is then encrypted with the first 4 sets of primes in the order that the user speciefied. They are encrypted by simply just + the int value of each character in the message with the 256 prime numbers.
5) The int value of each character in the message is then XOR with the int value of the password.
6) The int value is then finally + with the last 4 sets of primes in the order that the user speciefied.
7) To decrypt this, you just - the int value with the prime sets and then XOR the int value again.

This algorithm works fine when I dont use the XOR step. I cleaned the code up a little but and this is the output that it now produce:

Original: 104 101 108 108 111 
Encrypted: 44059732 44059727 44059736 44059736 44059741 
Decrypted: -26 -29 -22 -22 -11 

Here is the main function that calls the encryption:

 public static void main(String[] args) {
        String message = "hello";
        long[] plainText = new long[message.length()];
        long[] encrypted = new long[message.length()];
        long[] decrypted = new long[message.length()];

        CommandEncryption enc = new CommandEncryption("pwd", "01234567");
        plainText = enc.convertStringToLong(message);
        encrypted = enc.encryptData(plainText);
        decrypted = enc.decryptData(encrypted);

        System.out.print("Original: ");
        for(int i = 0; i < message.length(); i++) {
            System.out.print(plainText[i] + " ");
        }

        System.out.print("\nEncrypted: ");
        for(int i = 0; i < message.length(); i++) {
            System.out.print(encrypted[i] + " ");
        }

        System.out.print("\nDecrypted: ");
        for(int i = 0; i < message.length(); i++) {
            System.out.print(decrypted[i] + " ");
        } 
        System.out.println();
    }

Since you encrypt using XOR and decrypt using XOR, wouldn't it work if you just run the same method encryptData twice? Once to encrypt it and once to decrypt it, however in the first case you use the plain text message and in the second you use the cipher text

He adds a load of numbers befroe XORing, and a load more afterwards, so these need to be subtracted when decoding.
ps: Since they are all just added, I can't see the value of those arrays of primes. Just 8 big numbers would do the same thing. And since the XOR just affects the last byte of the long, it has no effect on most of the number anyway (just look athe encrypted values). Any why use long's when they get cast to int for the XOR anyway?

Edited 1 Year Ago by JamesCherrill

I may have the answer, but don't have the time to check it out fully. Anyway...

encrypt:
add first 4 sets of numbers
XOR
add last 4 sets of numbers

decrypt (actual):
subtract first 4 sets of numbers
XOR
subtract last 4 sets of numbers

decrypt (should be):
subtract last 4 sets of numbers
XOR
subtract first 4 sets of numbers

(or maybe I just mis-read it in a hurry)

I think the reverse of XOR is XOR itself as slavi mentioned???

public static void main(String[] args) {
  int num1 = Integer.parseInt("0101110110", 2);
  int num2 = Integer.parseInt("0010110100", 2);
  System.out.println("Int1: "+num1+" | "+Integer.toString(num1, 2));
  System.out.println("Int2: "+num2+" | "+Integer.toString(num2, 2));
  int num3 = num1 ^ num2;
  System.out.println("Int3: "+num3+" | "+Integer.toString(num3, 2));
  int num4 = num3 ^ num2;
  System.out.println("Int4: "+num4+" | "+Integer.toString(num4, 2));
}
/*
Output:
Int1: 374 | 101110110
Int2: 180 | 10110100
Int3: 450 | 111000010
Int4: 374 | 101110110
*/

Yes, a second XOR always takes you back to the original value.
That's not the real problem here. He has a load of additions, reversed by a load of subtractions. Mathematically the order of the additions or subtractions doeasn't affect the final result. But when you stick another operation (eg XOR) in the middle then it does matter which adds/subtracts you do before that operation, and which you do after it. And that's where I think this code goes wrong...

This question has already been answered. Start a new discussion instead.