This is the second challenge of Set 1 in The Cryptopals Crypto Challenges website. Previously, I spoke about these challenges and provided a walkthrough for the first challenge, if you haven't read them, here are the links:
- The Cryptopals Crypto Challenges
- The Cryptopals Crypto Challenges: Set 1 - Convert Hex to Base64
- Base64 Encoding / Decoding using Bitwise Manipulation in C++
For this challenge, you must write a method that takes two strings of fixed equal length and produce their XOR combination:
When you feed the following Hexadecimal string:
1c0111001f010100061a024b53535009181c
And perform an XOR operation against another Hexadecimal string:
686974207468652062756c6c277320657965
The method should return the following result:
746865206b696420646f6e277420706c6179
Like the first challenge, this is sort of a warmup and a simple challenge to tackle. Just to give you a heads up, every challenge that you solve in this set would all make sense, in the end, as the challenges will get tougher and much more interesting.
How do I solve this?
As I mentioned above, this problem is simple and pretty straightforward. In my previous post, I talked about Bitwise Manipulations and it's operators, I will be using the XOR (\^) operator, if you want to know more about it, check out my previous post. Also, I will reuse some of the functions that I had used in the first challenge. So let's dive in to the code:
Methods that are being reused:
//Hashmap that contain hex key and binary values
map<char, string> CryptoLib::gen_hex_table()
{
map<char, string> map;
map['0'] = "0000";
map['1'] = "0001";
map['2'] = "0010";
map['3'] = "0011";
map['4'] = "0100";
map['5'] = "0101";
map['6'] = "0110";
map['7'] = "0111";
map['8'] = "1000";
map['9'] = "1001";
map['a'] = "1010";
map['b'] = "1011";
map['c'] = "1100";
map['d'] = "1101";
map['e'] = "1110";
map['f'] = "1111";
return map;
}
//Convert hex to string
string CryptoLib::con_hex_2_bin(string hexStr)
{
map<char,string> m = gen_hex_table();
string newStr = "";
for(int i=0; i<hexStr.size(); i++)
{
if(isdigit(hexStr[i]))
{
newStr += m.find(hexStr[i])->second;
}
else
{
newStr += m.find(hexStr[i])->second;
}
// newStr += m.find(hexStr[i])->second;
}
return newStr;
}
//Convert binary to decimal
vector<int> CryptoLib::con_bin_2_dec(string str, double power)
{
vector<int> v;
string newStr = "";
istringstream iss(str);
string x;
while(iss >> x)
{
double p = power;
double decimal = 0.0;
for(int i=0; i<x.size(); i++)
{
if(x[i] == '1')
{
decimal += pow(2.0, p);
}
p--;
}
v.push_back((int)decimal);
}
return v;
}
//Add spaces between strings
string CryptoLib::add_spaces(string str, int spaces)
{
string newStr = "";
int count = 0;
for(int i=0; i<str.size(); i++)
{
// newStr += str[i];
if(count == spaces)
{
newStr += " ";
i--;
count = 0;
}
else
{
newStr += str[i];
count++;
}
}
return newStr;
}
//Convert ASCII to HEX
string CryptoLib::con_ascii_2_hex(string str)
{
stringstream ss;
for(int i=0; i<str.size(); i++)
{
ss << std::hex << (int)str[i];
}
return ss.str();
}
Implementation of the method:
//Fixed XOR implementation
string CryptoLib::fixedXOR(string str1, string str2)
{
//Check if the length of both the strings are equal
if(str1.size() != str2.size())
{
return "The strings are not of equal length.";
}
else
{
string newStr = "";
//Step 1. convert hex to binary of 8 bits
str1 = add_spaces(con_hex_2_bin(str1), 8);
str2 = add_spaces(con_hex_2_bin(str2), 8);
//Step 2. convert binary to decimal
vector<int> v1 = con_bin_2_dec(str1, 7.0);
vector<int> v2 = con_bin_2_dec(str2, 7.0);
//Step 3. XOR the decimals of v1 with decimals of v2
for(int i=0; i<v1.size(); i++)
{
//Get the char of the first string
unsigned char a = v1[i];
//Get the char of the second string
unsigned char b = v2[i];
//Perform XOR operation against each other
unsigned char c = a ^ b;
//Concatenate the string
newStr += c;
}
//ASCII result: the kid don't play.
//Final result - Convert the ASCII string to Hexadecimal
return con_ascii_2_hex(newStr);
}
}
Final code:
//CryptoPals Set 1 Challenge 2
#include "crypto.h"
int main()
{
CryptoLib crypt;
//The test cases provided
string str1 = "1c0111001f010100061a024b53535009181c";
string str2 = "686974207468652062756c6c277320657965";
cout << crypt.fixedXOR(str1, str2) << endl;
return 0;
}
Note: This solution and the library named crypto.h was built using the C++ programming language. The source code for this solution can be found on Github.
Stay tuned for the next challenge!