megacolorboy

Abdush Shakoor's Weblog

Writings, experiments & ideas.

The Cryptopals Crypto Challenges: Set 1 - Implement Repeating-Key XOR

Write a method that encrypts messages using the Repeating-Key XOR method with a given key.

This is the fifth challenge of Set 1 in The Cryptopals Crypto Challenges website. Previously, I spoke about these challenges and provided walkthroughs for the previous challenges, if you haven't read them, here are the links:

For this challenge, you have to implement a Repeating-Key XOR method to encrypt the following message:

Burning 'em, if you ain't quick and nimble
I go crazy when I hear a cymbal

With a given key:

ICE

The final message should look like this:

0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272
a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f

If you've already understood the concept of XOR and had no issues implementing both Fixed XOR Cipher and Single-Byte XOR Cipher, then this should be a piece of cake for you when it comes to implementing Repeating-Key XOR Cipher.

How does this work?

With Repeating-Key XOR, you'll sequentially apply each byte of the key (which is "ICE", in this case); the first byte of plaintext will be XOR'd against "I", the next "C", the next "E", then "I" again for the 4th byte, and so on.

You can use this method to encrypt anything you want. Emails, Passwords, Secret messages and so on. You'll definitely get a feel for it because things will get interesting after this challenge.

Let's dive in to the code:

Implementation of the method(s):

//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();
}

//Repeating Key XOR implementation
string CryptoLib::repeatingKeyXOR(string str, string key)
{
    string newStr = "";
    int count = 0;

    /*
        1. Perform XOR against each character of the message 
        against each character of the key. 
        So if the key was "ICE" and the message is "abcdefg",
        it would be "a" against "I", then "b" against "C" and "c" against "E"
        but once it reaches the key's limit, you start again from the beginning
        of the key, which should be like: "d" against "I", "e" against "C" and so on.
    */
    for(int i=0; i<str.size(); i++)
    {
        unsigned char a = key[count];
        unsigned char b = str[i];
        unsigned char c = b ^ a;

        newStr += c;

        if(count == key.size()-1)
        {
            count = 0;
        }
        else
        {
            count++;
        }
    }

    //2. Convert the ASCII message to Hexadecimal
    string final = "0";
    final += con_ascii_2_hex(newStr);
    return final;
}

Final code:

//Cryptopals Set 1 Challenge 5
#include "crypto.h"

int main()
{
    CryptoLib crypt;

    //Test cases provided
    string str = "Burning 'em, if you ain't quick and nimble I go crazy when I hear a cymbal";
    string key = "ICE";

    cout << "ENCODED: " << crypt.repeatingKeyXOR(str, key) << 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!

The Cryptopals Crypto Challenges: Set 1 - Single-Byte XOR Cipher

Write a method that decrypts a hexadecimal message that has been XOR'd against a single character.

This is the third challenge of Set 1 in The Cryptopals Crypto Challenges website. Previously, I spoke about these challenges and provided walkthroughs for the previous challenges, if you haven't read them, here are the links:

For this challenge, you have to write a method that decodes a Hexadecimal string:

1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736

That has been XOR'd against a single character. You must find the key and decrypt the message.

If you have read the previous article, it was clearly setup for this problem. There are so many ways to solve this problem but the most efficient way to solve it is by using a Frequency table.

Assuming the message is supposed to be in English, when decrypted, we need to only generate a frequency table using the given Hexadecimal string that shows the frequencies of each alphabet. The character that has the highest frequency is the key required, which is then used to perform an XOR (\^) operation against each character, to decrypt the encrypted message.

Let's have a look at the code:

//Return Character frequency of a string
map<char, int> CryptoLib::frequency_table(string str)
{
    map<char, int> m;
    map<char, int>::iterator it;

    for(int i=0; i<str.size(); i++)
    {
        char ch = str[i];
        it = m.find(ch);

        if(it == m.end())
        {
            m.insert(make_pair(ch,1));
        }
        else
        {
            it->second++;
        }
    }

    return m;
}

//Return character with the highest frequency
char CryptoLib::ret_high_freq_char(map<char, int> m)
{
    int max_count = 0;
    char max_char;

    for(auto p: m)
    {
        if(isalpha(p.first))
        {
            if(p.second > max_count)
            {
                max_char = p.first;
                max_count = p.second;
            }
        }
    }
    return max_char;
}

//Single Byte XOR
string CryptoLib::singleByteXOR(string str)
{
    string newStr = "";

    //1. Convert Hexadecimal to Binary
    str = add_spaces(con_hex_2_bin(str), 8);

    //2. Convert Binary to Decimals
    vector<int> v = con_bin_2_dec(str, 7.0);


    // What's happening here?
    // 4. Generate a frequency table using the characters from the ASCII string
    // 5. Look for characters that are English and also has the highest frequency
    // 6. The character that has the highest frequency is the KEY!

    //The key
    unsigned char a = toupper(ret_high_freq_char(frequency_table(con_dec_2_ascii(v))));

    //7. Perform XOR with the KEY against each character
    for(int i=0; i<v.size(); i++)
    {
        unsigned char b = v[i];
        unsigned char c = b ^ a;
        newStr += c;
    }

    //8. Decoded message
    return newStr;
}

Final code:

//CryptoPals Set 1 Challenge 3
#include "crypto.h"

int main()
{
    CryptoLib crypt;

    //Test case provided
    string str = "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736";
    cout << "DECODED: " << crypt.singleByteXOR(str) << endl;
    return 0;
}   

Decrypted message:

Key with the highest frequency: 'X'
Message: Cooking MC's like a pound of bacon

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!

The Cryptopals Crypto Challenges: Set 1 - Detect Single-Character XOR

Write a method that derives which string that has a length of 60 characters has been encrypted using Single-Byte XOR cipher.

This is the fourth challenge of Set 1 in The Cryptopals Crypto Challenges website. Previously, I spoke about these challenges and provided walkthroughs for the previous challenges, if you haven't read them, here are the links:

For this challenge, given a list of encrypted strings, you must derive which string (that has a length of 60 characters) is encrypted using Single-Byte XOR Cipher.

Similar to the previous post, this is more about breaking the Single-Byte XOR Cipher technique. Remember, you can solve this challenge only if you were able to solve the previous challenge because you'll have to tweak some of the previous code in this challenge.

How to detect Single-Byte XOR?

In the previous challenge, we're able to determine the key as we had one string but how do we do that with 300+ strings in a file except now that we also have to determine if the string is encrypted using Single-Byte XOR Cipher or not?

Here's comes the interesting part:

  1. Select the string that has the most english letters from the file
  2. Perform a Brute-force XOR on the string with the most english letters in which each character is XOR'd against every character from the ASCII table (256 characters)
  3. Pick the most english string after brute-forcing with each character
  4. Display the final result

Let's have a look at the code:

Implementation of the method(s):

//Return Character frequency of a string
map<char, int> CryptoLib::frequency_table(string str)
{
    map<char, int> m;
    map<char, int>::iterator it;

    for(int i=0; i<str.size(); i++)
    {
        char ch = str[i];
        it = m.find(ch);

        if(it == m.end())
        {
            m.insert(make_pair(ch,1));
        }
        else
        {
            it->second++;
        }
    }

    return m;
}

//Return integer with the highest frequency of alphabets
int CryptoLib::high_frequency_count(map<char,int>m)
{
    int count = 0;
    for(auto p: m)
    {
        if(isalpha(p.first))
        {
            // cout << p.first << ":" << p.second << " ";
            count += p.second;
        }
    }
    return count;
}

//Detect string with Single Byte XOR
string CryptoLib::detectSingleByteXOR(vector<int> maxV)
{
    string final = "";
    int maxCount = 0;

    /*
        2. Perform a Brute-force XOR on the string that has
        the most english letters in which each character is XOR'd against
        every character from the ASCII table (256 characters)
    */
    for(int i=0; i<256; i++)
    {
        string temp = "";
        unsigned char a = i;
        for(int j=0; j<maxV.size(); j++)
        {
            unsigned char b = maxV[j];
            unsigned char c = b ^ a;
            temp += tolower(c);
        }

        //3. Select the string that has the most english letters. again.
        int count = high_frequency_count(frequency_table(temp));
        if(count > maxCount)
        {
            maxCount = count;
            final = temp;
        }
    }

    //4. Display the most "english" text as the final result
    return final;
}

Final code:

//Cryptopals Set 1 Challenge 4
#include "crypto.h"

int main()
{
    CryptoLib crypt;

    ifstream infile;
    string str;
    int maxCount = 0;
    string maxString = "";
    vector<int> maxV;

    infile.open("enctext.txt");

    //if the file is not there
    if(!infile)
    {
        cout << "Unable to open the file";
        exit(1);
    }

    while(infile >> str)
    {
        //Only look for strings with 60 char length
        if(str.size() == 60)
        {
            str = crypt.add_spaces(crypt.con_hex_2_bin(str), 8);
            vector<int> v1 = crypt.con_bin_2_dec(str, 7.0);
            string newStr = crypt.con_dec_2_ascii(v1);

            //1. Select the string that has the most english letters
            int count = crypt.high_frequency_count(crypt.frequency_table(newStr));
            if(count > maxCount)
            {
                maxCount = count;
                maxString = newStr;
                maxV = v1;
            } 
        }
    }

    //2. Pass the list of decimals to the function (for now)
    cout << crypt.detectSingleByteXOR(maxV) << endl;
    return 0;
}

Decrypted message:

Message: Now that the party is jumping.

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!

The Cryptopals Crypto Challenges: Set 1 - Fixed XOR

Write a method that takes two strings of fixed equal length and produce their XOR combination.

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:

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!

Base64 Encoding / Decoding using Bitwise Manipulation in C++

An alternate solution to the previous post on how to encode/decode hexadecimals to Base64 and vice-versa using Bitwise Manipulation.

In the previous post, I provided the walkthrough for the first challenge of Set 1 in The Cryptopals Crypto Challenges website but then I realized that I didn't write a method that could decode the Base64 string back to it's original Hexadecimal format. So I went back to the website again and found an important rule that I should have not ignored, at the very beginning:

Cryptopals Rule:

Always operate on raw bytes, never on encoded strings. Only use Hex and Base64 for pretty-printing.

Although, the solution I had provided in the first one works, but there's no way that I could go back to displaying the original Hexadecimal string. So I went on Wikipedia and did some research on Base64 and I figured out that I should brush up my knowledge on Bitwise Manipulation as I never had a use for it until now.

In this post, which should be pretty much straightforward (and probably longer too), I will be talking about Bitwise Manipulation and it's operators and also provide an alternate walkthrough for the first challenge of The Cryptopals Crypto Challenges.

What is Bitwise Manipulation?

Bitwise Manipulation is a low-level, algorithmic technique used to manipulate bits or data that are shorter than a word. This technique is mostly used on embedded controls, data compression, encryption algorithms and error-detection.

As I mentioned above, most programmers don't get to use this technique a lot as most programming languages allows the programmer to work on abstractions directly instead of bits that represent those abstractions.

A program that implements bitwise manipulation, makes use of the following operators:

  • Bit Shifts (<< / >>)
  • AND (&)
  • OR (|)
  • NOT (!)
  • XOR (\^)

Bit Shift operations

Let's take a look at both the left << and right >> shift operators. So if you use either of them, you would be shifting x number of bits to left or right in a variable.

Let's say we have the number x = 4, and it's binary form is 00000100 and we wanted to shift by 4 bits to the left, we just have to call x << 4, the result would be 00100000, which means x = 64. Shifting to the left is the equivalent of multiplication by the power of n because 4x2^4^ = 64. Similarly, shifting to the right is the equivalent of division by the power of n because 4 / 2^4^ = 4 and it's binary form would be 00000100.

AND, OR and NOT operations

The bitwise operator AND is useful, when you want to check a bit is on or off i.e. 0 or 1. Whereas for the bitwise operator OR is the exact opposite, if either bit is on, then the result will be 1, else it will be 0. Finally, the bitwise operator NOT is used for inverting the bits in a binary, for example, if you had a binary string of 00101000, you'd get 11010111, it is used best when you want to turn off a bit combined with the AND operator.

XOR operator

Relax, this ain't scary, this is also known as Exclusive-OR. This operator works when both bits that are compared are either 0 or 1, then the result will be 0, else it will be 1. So if you perform an XOR on 01001000 and 01000100, the result will be 00001100.

I hope that by now, you must have understood the basic concept of Bitwise Manipulation, if not, then spend some time reading about it before scrolling down to the next topic i.e. on how it's applied to encode and decode Hexadecimal strings to Base64 strings and vice-versa.

Base64 Encoding

Before you get started, please keep a couple of things in your mind:

  • Each Hexadecimal character has 4 bits (Base 16)
  • Each Base64 character has 6 bits (Base 32)
  • We will be using the standard MIME-Base64 Encoding, thus we will have to use '+' and '/' characters as well

Now that we have the facts, doing a simple math states that every 3 Hexadecimal characters is equal to 2 Base64 characters, since the least common multiple between 4 and 6 is 12. In order to do this, we are going to make use of our Bitwise Operators, let's have a look at the method:

//Base64 Encoder
string CryptoLib::b64_encode(string str)
{
    string newStr = "";
    string ref = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    //Number of bytes per 12 bits
    int bytes = str.size() / 3;
    int padding = str.size() % 3;

    //Padding must be either 0 or 1
    if(padding > 1)
    {
        return newStr;
    }

    //Number of characters to be encoded is 3

    int count = bytes * 3;

    unsigned long long h = 0;

    int i = 0;
    for(i=0; i<count; i+=3) //iterate every 3 chars
    {
        //Get every 3 chars
        char a[2] = {str[i], 0};
        char b[2] = {str[i+1], 0};
        char c[2] = {str[i+2], 0};

        //Now, convert each hex character (base 16) to it's equivalent decimal number
        //and merge them into one variable
        h = strtoull(a, nullptr, 16) << 8; //shift left by 8 bits
        h |= strtoull(b, nullptr, 16) << 4; //shift left by 4 bits
        h |= strtoull(c, nullptr, 16); //no shift required only the first 2 characters need

        //HEX: 0x3F -> DEC: 63 -> ASCII: ?

        newStr += ref[0x3F & (h >> 6)]; //first b64 char; shift to right by 6 bits
        newStr += ref[0x3F & h]; //second b64 char
    }

    //if padding is required
    //Follows the same pattern as the above.
    if(padding == 1)
    {
        char a[2] = {str[i], 0};
        h = strtoull(a, nullptr, 16) << 8; // shift left by 8 bits
        newStr += ref[0x3F & (h >> 6)];
        newStr += '='; //add this towards the end of the encoded string
    }

    return newStr;
}

If you're wondering on how to convert an ASCII string, all you have to do is convert the ASCII string to a Hexadecimal string and then use this method to give you the Base64 encoded string.

Base64 Decoding

What if you wanted to get back to the original string? Well, that's what we are going to do next. Unlike the previous post, you might have noticed that I didn't use any Hashmaps for encoding the Base64 characters, I wanted to try a different approach and also thought of increasing speed and efficiency and of course, keeping it simple.

Let's take a look at the method:

//Base64 Decoder
string CryptoLib::b64_decode(string str)
{
    string newStr = "";
    string ref = "0123456789abcdef";

    //Check if this is a valid b64 string
    if(str.size() % 2 != 0)
    {
        return newStr;
    }

    //Number of bytes for hexadecimals
    int bytes = str.size() / 2;
    int count = bytes build.sh content convert.sh make_entry.py output ssg.py ssg.pyc templates transfer.sh venv 2;

    unsigned long long h = 0;
    for(int i=0; i<count; i+=2) //iterate every 2 chars
    {
        for(int j=0; j<2; j++)
        {
            h <<= 6; //shift 6 bits to the left

            //Check if the value is in the range of A-Z
            if(str[i+j] >= 0x41 && str[i+j] <= 0x5a)
            {
                h |= str[i+j] - 0x41;
            }
            //Check if the value is in the range of a-z
            else if(str[i+j] >= 0x61 && str[i+j] <= 0x7a)
            {
                h |= str[i+j] - 0x47;
            }
            //Check if the value is in the range of 0-9
            else if(str[i+j] >= 0x30 && str[i+j] <= 0x39)
            {
                h |= str[i+j] + 0x04;
            }
            //Check if the value is a '+'
            else if(str[i+j] == 0x2b)
            {
                h |= 0x3e;
            }
            //Check if the value is a '/'
            else if(str[i+j] == 0x2f)
            {
                h |= 0x3f;
            }
            //Check if the value is a '='
            else if(str[i+j] == 0x3d)
            {
                if(count - (i+j) == 1)
                {
                    newStr += ref[0xf & (h >> 8)];
                }
            }
        }
        //Shift to the right by 8 bits
        newStr += ref[0xf & (h >> 8)];
        //Shift to the right by 4 bits
        newStr += ref[0xf & (h >> 4)];
        newStr += ref[0xf & h];
    }

    return newStr;
}

In the final code, I just converted an ASCII string to Base64 string, let's have a look at it:

Methods to convert ASCII string to Hexadecimal string and vice-versa:

//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();
}

//Convert HEX to ASCII
string CryptoLib::con_hex_2_ascii(string str)
{
    string newStr = "";
    str = add_spaces(con_hex_2_bin(str), 8);
    vector v = con_bin_2_dec(str, 7.0);

    for(int i=0; i<v.size(); i++)
    {
        newStr += (char)v[i];
    }
    return newStr;
}

Final Code:

//CryptoPals Set 1 Challenge 1
#include "crypto.h"

int main()
{
    CryptoLib crypt;

    string str = crypt.con_ascii_2_hex("Hello World");
    string enc = crypt.b64_encode(str); 
    cout << "ENCODED: " << enc << endl;

    string dec = crypt.con_hex_2_ascii(crypt.b64_decode(enc));
    cout << "DECODED: " << dec << 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.

Hope you guys liked reading this article!

Until next time, then!

The Cryptopals Crypto Challenges: Set 1 - Convert Hex to Base64

Convert Hexadecimal strings to encoded Base64 strings.

This is the first challenge of Set 1 in The Cryptopals Crypto Challenges website. If you want to know more about these challenges, look at my previous post.

For this challenge, you need to be able to convert Hexadecimal strings to encoded Base64 strings:

The string:

49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d

Should produce:

SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t

Not only is this challenge just a warmup but it is also designed to make you feel comfortable in dealing with raw bytes as Base64 is used to encode binary information and Hexadecimal is used to view the raw bytes.

How to convert from Hexadecimal to Base64?

Well, it's simpler than you think! You will have to go through the following steps:

  1. Convert hexadecimal string to binary string
  2. Split the binary string into 4 pieces of 6 bits each
  3. Convert the binary string to decimal
  4. Compare each decimal against each character in a reference string of 64 characters

Convert hexadecimal string to binary string

Before converting to binary, you should compare each character against a hashmap table of hardcoded hexadecimal keys and binary values.

//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;
}

Split the binary string into 4 pieces of 6 bits each

Base64 represents data in the form of ASCII format that follows a Radix-64 representation. Each character is picked from a set of 64 characters, which means that I'll only need 6 bits represent each character because 26 = 64 characters.

//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 the binary string to decimal

Before converting, you should know that a decimal number is equal to the sum of binary digits (d~n~) times their power of 2 (2n).

Let's say you have a binary string of 111001, it's decimal would be 1x25 + 1x24 + 1x23 + 0x22 + 0x21 + 1x20 = 57

//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;
}

Compare each decimal against each character in a reference string of 64 characters

At this stage, all you have to do is find and concatenate each character (using the reference string) based on each decimal and return your encoded Base64 string as the final output.

//Convert HEX to Base 64
string CryptoLib::con_hex_2_b64(string str)
{
    string b64 = "";
    string ref = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    string newStr = add_spaces(con_hex_2_bin(str), 6);

    vector<int> v = con_bin_2_dec(newStr, 5.0);

    for(int i=0; i<v.size(); i++)
    {
        b64 += ref[v[i]];
    }

    return b64;
}

Here's the final section of the code:

//CryptoPals Set 1 Challenge 1
#include "crypto.h"

int main()
{
    CryptoLib crypt;

    //Test case provided from the site
    string str = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
    cout << crypt.con_hex_2_b64(str) << 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.

The Cryptopals Crypto Challenges

Came across an interesting website that hosts cryptographic challenges based on real world cryptography.

Last week, I came across an interesting website named The Cryptopals Crypto Challenges (also known as The Matasano Crypto Challenges) that hosts cryptographic challenges based on real-world cryptography that makes use of various ciphers and secure protocols.

What is it about?

These challenges were developed by a security team called NCC Security, which is developed as a tool for teaching Cryptography.

Currently, there are eight sets of problems in which each set gets progressively harder as you solve them. As I'm writing this post, I'm solving the first set of problems, these problems are designed in such a way that you get to build own cryptographic functions/utilities and exploit them. Most importantly, not only do these challenges give you an overview on how to build secure cryptographic systems but also you'll get an understanding on how they're being attacked.

In the first few challenges, I was exposed to some crypto math but these concepts weren't that hard as it was more practical and gentler:

Also, I found myself using different techniques to solve these challenges such as:

  • String manipulation
  • Lookup tables / Hashmaps
  • Conversion of string to integer and vice-versa
  • Bitwise operators

Like I had mentioned above, this is also designed as a tool to learn cryptography, which means you don't really need to have prior knowledge of cryptography and security. It's all about doing your own research on various algorithms, implementing the solution and then breaking your own solution.

Why do I want to do this?

I found it as a good opportunity to sharpen my C++ programming skills and learn more about cryptographical theory and it's applications. If you're curious and passionate enough to solve puzzles, this is your chance!

What's next?

I will be posting walkthroughs (on how I solved every problem in each set) on my blog and also provide solutions to those problems on my GitHub repository.

Stay tuned!

New feature: Share your reaction

Rolled out a new feature to collect emotional intelligence, which would help me to make better blog posts in the future.

Last night, I was thinking on how to improve my blog posts and post better articles. My head went through questions like:

  • What do people feel when they read my articles?
  • Do they find it interesting?
  • Is it boring?
  • Is it likeable?

But, in order to do that, I'll require some simple analytics on how people react to my articles on my blog. Taking inspiration from web applications like Facebook, Instagram, Twitter and Medium, I decided to build a small feature named "Share your reaction", from scratch, that would contain six different emotions.

The six different emotions used in this new feature

From today onwards, you can start reacting to my blog posts by clicking the "React!" button (which can be found below every article), select an emotion and help me improve and post better articles in my blog in the future.

In case, you're wondering, the data that is collected is completely anonymous as I'm not collecting any IP address or any of your private and sensitive information.

Hope you guys like the new feature!