How to break a single byte key XOR encryption
Overview
XOR encryption belongs to the category of symmetric encryption, where the same key is used to encrypt and decrypt the message.
Note: To read more about XOR encryption, click here.
Breaking XOR encryption
Single byte key XOR encryption is easier to break because the key is only 8 bits long. The following steps define a method of breaking XOR encryption:
Step 1
Convert the cipher text into binary and make groups of 8 bits each.
Since the example cipher text is in hexadecimal, we will convert each character into bits of length four and concatenate two characters to generate one byte each.
#include <iostream>#include <bits/stdc++.h>using namespace std;//function to convert hexadecimal string to binarystring HexToBin(string hexdec){long int i = 0;string binary = "";while (hexdec[i]) {switch (hexdec[i]) {case '0':binary += "0000";break;case '1':binary += "0001";break;case '2':binary += "0010";break;case '3':binary += "0011";break;case '4':binary += "0100";break;case '5':binary += "0101";break;case '6':binary += "0110";break;case '7':binary += "0111";break;case '8':binary += "1000";break;case '9':binary += "1001";break;case 'A':case 'a':binary += "1010";break;case 'B':case 'b':binary += "1011";break;case 'C':case 'c':binary += "1100";break;case 'D':case 'd':binary += "1101";break;case 'E':case 'e':binary += "1110";break;case 'F':case 'f':binary += "1111";break;}i++;}return binary;}int main(){// cipher textstring hexdec = "1b071002051f0e131f";// i is set to traverse through cipher textint i = 0;// counter helps us in making byte sized groupsint counter=0;// store binary equivalent for each hexstring* binary = new string[hexdec.length()];// loop for the length of the cipher textwhile(hexdec[i]){// group two hex characters togetherstring group;group.push_back(hexdec[i]);if(hexdec[i+1])group.push_back(hexdec[i+1]);//store the binary equivalent in binary arraybinary[counter] = HexToBin(group);cout<<binary[counter] <<endl;counter++;i=i+2;}return 0;}
Explanation
The code above converts hexadecimal string to binary:
- Lines 6-73: The
HexToBin()converts the hexadecimal string to binary. - It receives a string in hexadecimal and converts each character to binary using case statements.
- Lines 84-97: The
whileloop transverses through the entire hexadecimal string in groups of 2. - A group of 2 characters is sent to
HexToBin()function. - Binary array stores the result of each group.
Step 2
Since the key is one byte in length, it can be represented in 256 possibilities (
We can use a for loop to generate all the 256 keys and store them in binary.
#include <iostream>#include <bits/stdc++.h>using namespace std;int main() {string* keys = new string[256];cout<<"Set of possible keys: "<<endl;for(int i=0; i<256; i++){// convert to decimal with a bitset of 8string s = bitset<8>(i).to_string();keys[i] = s;cout<<s<<endl;}return 0;}
Explanation
The code generates 256 different keys:
- Lines 9-14: The
forloop converts each key into a bitset of 8 length - The
keys[]stores the binary of the generated possible encryption keys.
Step 3
XOR each key with the cipher text to generate a decrypted text. In simpler words, XOR the results from steps 1 and 2.
The resulting binary is then converted to English using ASCII values for every 8 bits, assuming the text is written in the English language.
Step 4
Score each of the 256 decrypted texts based on the "English," assuming that the plain text is written in the English language. The key that generates a decrypted text with the highest score is assumed to be the encryption key.
We can use different methods to score the English of the decrypted text. However, we'll use character frequency analysis here.
#include <iostream>using namespace std;float letterScores[26] = {8.167, 1.492, 2.782,4.253, 12.702, 2.228, 2.015, 6.094, 6.966,0.153, 0.772, 4.025, 2.406, 6.749, 7.507,1.929, 0.095, 5.987, 6.327, 9.056, 2.758,0.978, 2.360, 0.150, 1.974, 0.074 };int calculateScore(string str){// convert string to lower casefor(int i=0; i < str.length(); i++)str[i] = tolower(str[i]);int score = 0;for(int i=0; i < str.length(); i++){// if space is detected, add 15 to the scoreif(str[i] == ' ')score += 15;else// add the score of character using letterScores arrayscore += letterScores[str[i] - 97];}return score;}int main() {string str = "Hello World";cout << "Score: "<<calculateScore(str)<<endl;return 0;}
Explanation
We assume that the text is in English, and the code scores the decrypted text using frequency analysis.
- Lines 4-8: We have the
letterScoresas a float array that contains thescoreof each character. - Lines 11-12: We convert the string to lower case for easy
scorecalculation. - Lines 17-22: We update the
scoreusingletterScores. - Line 21: We subtract 97 from the character's ASCII to reach the first index of
letterScoresarray.
Step 5
Decrypted text with the highest English score is the original deciphered text, and the key used to generate it is the actual key used in the encryption process earlier.
Note: If we have a part of the original message and we XOR it with the cipher text, it will give us the encryption key.
Free Resources