2
votes

I have implemented XOR encryption algorithm like so:

string XOR(string data, const char* key)
{
    string xorstring = data; //initialize new variable for our xordata
    for (int i = 0; i < xorstring.length(); i++) { //for loop for scrambling bits in the string
    xorstring[i] = data[i] ^ key[i]; //scrambling the string/descrambling it
    } 
    return xorstring;
}

Which works just fine, like: string ciphertext = XOR("test", "1234"); will return the ciphertext and when decrypting:string plaintext = XOR(ciphertext, "1234"); it will return 'test'.

So, I wanted to create an algorithm that would break the xor cipher by brute forcing, so basically trying to decrypt the ciphertext with every possible key combination.

It (should) work like this:

  • generate strings from an character array of alphabet
  • xor(decrypt) the given ciphertext with the given string to get plaintext
  • after that, xor(encrypt) the generated plaintext and compare it in if statement to see if it matches with the original ciphertext
  • if it matches, the correct key was found to decrypt the ciphertext.

Simple as that, but I found my self struggling with the algorithm:

const char Numbers[11] = "0123456789";
const char AlphabetUpper[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char AlphabetLower[27] = "abcdefghijklmnopqrstuvwxyz";

string XOR(string data, const char* key)
{
   string xorstring = data; //initialize new variable for our xordata
   for (int i = 0; i < xorstring.length(); i++) { //for loop for scrambling   bits in the string
    xorstring[i] = data[i] ^ key[i]; //scrambling the string/descrambling it
   }
   return xorstring;
 }

 string cipher, plain; //store the ORIGINAL ciphertext and plaintext

 int main()
 {
    plain = "test"; //set the plaintext
    cipher = XOR(plain, "1234"); //encrypt it with the xor function

    cout << plain << endl;  //output
    cout << cipher << endl; //output

    cout << "press enter to start bruteforcing!" << endl;
    getchar();

    while (true) //loop for bruteforcing
    {
       static int stringlength = 1; //the keylength starts from 1 and then
       //expands to 2,3,4,5, etc...
       BruteForce(stringlength, cipher, ""); //call the brute force function
       stringlength++; //increment the keylength
    }
    return 0;
}

void BruteForce(int length, string ciphertext,  string tempKey)
{
    static int count = 0; // for counting how many times key was generated
    string decipher, recipher; //for storing new XORed strings.
    if (length == 0) 
    {
       //decrypt the given ciphertext with the random key
       decipher = XOR(ciphertext, tempKey.c_str());
       //encrypt it again with the same key for comparison
       recipher = XOR(decipher, tempKey.c_str());

       cout << deciphered << endl; //output

       //compare the two ciphertexts
       if (ciphertext == recipher)
       {
         //....
          cout << "Key found! It was: '" << tempKey << "'" << endl;
          cout << "it took " << count << " iterations to find the key!";
          getchar();
       }
      return;
   }
   count++;
   //generate the keys.
   for (int i = 0; i < 26; i++) {
       std::string appended = tempKey + AlphabetLower[i];
       BruteForce(length - 1, ciphertext, appended);
    }
    for (int i = 0; i < 26; i++) {
       std::string appended = tempKey + AlphabetUpper[i];
       BruteForce(length - 1, ciphertext, appended);
     }
    for (int i = 0; i < 10; i++) {
       std::string appended = tempKey + Numbers[i];
       BruteForce(length - 1, ciphertext, appended);
   }
}

The algorithm does not work, for an unknown reason.

Very bizarre, in theory it should work. When the program is ran, it says the key was found on every execution of the bruteforce() function. Try it your self. Could someone point out that what I am doing wrong here? Help is appreciated. Thanks.

2
The XOR function may be wrong because it doesn't check the length of key and it may cause buffer overrun or read meaningless values. - MikeCAT
You can't brute-force a one-time pad (i.e. a xor cipher where the key was only used once). It's mathematically impossible to break the cipher. - interjay

2 Answers

3
votes

It doesn't work because your task is impossible. The one time pad (xor) has a property known as perfect secrecy which means your cipher text can be decrypted to any plain text with equal probability. So it's impossible to know which plain text was the original.

For your scheme specifically (message XOR key) XOR key is always just the message back again.

3
votes

This is the property of XOR operations: for every key you would find that

message XOR key XOR key == message

So your way to check that key is correct will indeed return all possible keys.

Moreover, say you have an encrypted message E. Then, for any possible plain text message M you will always find a key K so that

E = M xor K

(though such K can contain arbitrary chars, not just letters etc.) Therefore if you allow arbitrary chars in K, then the cypher is unbreakable even in theory (see one-time pad).

In case you allow only letters and digits in K, not every plain-text message can be received from a given encrypted message. However, you will need some more information on what the plain text could have been to detect "true" message from wrong ones (for example, knowing that plain text contains only letters, or that it is a valid English text, etc.), and you will need to check for this in your code. Anyway, I guess that you will get many possible plain texts even with this additional heuristics.