megacolorboy

Abdush Shakoor's Weblog

Writings, experiments & ideas.

The Cryptopals Crypto Challenges: Set 1 - AES in ECB Mode

Decrypt a Base64 encoded file that is encrypted with an AES-128 Cipher in ECB mode.

This is the seventh 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 are given a file, which contains a ciphertext that has been encrypted using AES-128 Cipher with ECB (Electronic Codebook) mode and then encoded using Base64. Decrypt it.

In order to decrypt it, you are given a key:

YELLOW SUBMARINE

What is AES?

Advanced Encryption Standard a.k.a Rjindael, which was developed by two belgian cryptographers, Vincent Rijmen and Joan Daemen. Rjindael is a family of ciphers with various block and key sizes.

AES-128 is commonly used but there are also larger key sizes such as 192 and 256 bits. Similar to XOR cipher, it uses the same key to encrypt and decrypt the message. Till date, there isn't any publication that states if whether AES is broken but even if you were to break it, it will take atleast a billion years with a supercomputer, which could beyond the age of the universe.

What is ECB Mode?

What if your plaintext is longer than (in this case, 128 bits) the keysize? This is where ECB comes into the picture. ECB (Electronic Codebook) is a cipher mode that is used to repeat the key until it covers the entire plaintext (similar to Repeating-Key XOR Cipher) and then each block is independently encrypted using the AES algorithm to produce the desired ciphertext.

This challenge is not that hard, in fact, it's completely trivial and more like an introduction of AES Cipher. There are so many ways to solve this problem but I chose to solve this problem using OpenSSL and other commandline tools such as xxd (used to print the hexdump of a file) on my UNIX terminal.

Here's the solution:

openssl enc -aes-128-ecb -d -a -in secret.txt -K $(echo "YELLOW SUBMARINE" | xxd -p) -iv 1 | head

This is the decrypted message:

I'm back and I'm ringin' the bell
A rockin' on the mike while the fly girls yell
In ecstasy in the back of me
Well that's my DJ Deshay cuttin' all them Z's
Hittin' hard and the girlies goin' crazy
Vanilla's on the mike, man I'm not lazy.

I'm lettin' my drug kick in
It controls my mouth and I begin
To just let it flow, let my concepts go

Initially, I was planning to write an implementation of AES for fun, but then I decided to make it a side project that I can work on as there are a lot of things about AES that I'd like to talk about in the future.

Stay tuned for the next challenge!

Hamming Distance Algorithm in C++

An article about the Hamming Distance algorithm that will be used in the next challenge.

This is a short article about the Hamming Distance algorithm, which will be used in The Cryptopals Crypto Challenges: Set 1 - Break Repeating-Key XOR challenge.

In Challenge 6, the first step states that you have to write a function to compute the edit distance/Hamming distance between two strings:

this is a test

And

wokka wokka!!!

When this function is executed, the expected result must be 37. If you we're able to make this function work, you can proceed with the next steps in the challenge.

What is Hamming Distance?

Applied in domains like Cryptography, Information theory and Coding theory, Hamming distance is just the number of differing bits between two strings of equal length. Named after the American Mathematician, Richard Hamming, this algorithm mainly used for Error Detection and Error Correction (and yes, this also makes use of Bitwise Operators).

Using the example above, let's see how this works, in theory:

ASCII Format: this is a test
Binary Format: 011101[0][0] 01101[0][0][0] 011010[0]1 011[1][0]011 0[0]10000[0] 0[1]10[1]00[1] 01110[0]11 0[0]10[0][0][0][0] 0110[0]0[0]1 0[0]10[0]0[0][0] 011[1]0[1]0[0] 0[1]100[1]01 0[1]1[1]00[1]1 0[1]1[1]0[1]0[0]

ASCII Format: wokka wokka!!!
Binary Format: 011101[1][1] 01101[1][1][1] 011010[1]1 011[0][1]011 0[1]10000[1] 0[0]10[0]00[0] 01110[1]11 0[1]10[1][1][1][1] 0110[1]0[1]1 0[1]10[1]0[1][1] 011[0]0[0]0[1] 0[0]100[0]01 0[0]1[0]00[0]1 0[0]1[0]0[0]0[1]

As per the given example, when you count the number of differing bits (the bits marked in brackets) between the two strings, the result is 37.

With help of Google and Wikipedia, I was able to build an implementation of this algorithm using the C++ programming language:

//Hamming Distance
int CryptoLib::hamming_distance(string str1, string str2)
{
    int count=0;
    for(int i=0; i<str1.size(); i++)
    {
        int partial = (str1[i] & 0xFF) ^ (str2[i] & 0xFF);
        while(partial)
        {
            count += partial & 1;
            partial = partial >>1;
        }
    }
    return count;
}

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 found this article useful!

Adios Amigo!

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

Write a method that decodes a message which is encrypted using the Repeating-Key XOR cipher.

This is the sixth 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 are given a file, which contains a ciphertext that has been encrypted using Repeating-Key XOR and then encoded using Base64. Decrypt it.

According to the problem description on the website:

It is officially on, now.

This challenge isn't conceptually hard, but it involves actual error-prone coding. The other challenges in this set are there to bring you up to speed. This one is there to qualify you. If you can do this one, you're probably just fine up to Set 6.

Well, conceptually, this may not be the hardest but practically, it is the first hardest challenge in this set and it really did take me a while to understand how to decrypt the ciphertext through trial-and-error despite the instructions given on the website. In this challenge, it's more like connecting all the puzzles and looking at the big picture, in this case, all of the previous code that I had written, is to break the Repeating-Key XOR cipher.

How to break it?

The challenge had given some steps to follow. Here's how:

  1. Let KEYSIZE be the guessed length of the key; try values from 2 to (say) 40
  2. Write a function to compute the edit distance/Hamming distance between two strings. To know more about it, click here
  3. For each KEYSIZE, take the first KEYSIZE worth of bytes, and the second KEYSIZE worth of bytes, and find the edit distance between them. Normalize this result by dividing by KEYSIZE
  4. The KEYSIZE with the smallest normalized edit distance is probably the key. You could proceed perhaps with the smallest 2-3 KEYSIZE values. Or take 4 KEYSIZE blocks instead of 2 and average the distances
  5. Now that you probably know the KEYSIZE: break the ciphertext into blocks of KEYSIZE length
  6. Now transpose the blocks: make a block that is the first byte of every block, and a block that is the second byte of every block, and so on
  7. Solve each block as if it was single-character XOR. You already have code to do this
  8. For each block, the single-byte XOR key that produces the best looking histogram is the repeating-key XOR key byte for that block. Put them together and you have the key

Let's dive in to the code (I hope the comments, help you out!):

Implementation of the method(s):

//Single Byte XOR V2 - a better version
string CryptoLib::singleByteXOR_V2(string str, char key)
{
    //Don't forget to add a NULL character to the string, it broke when I didn't add it previously.
    string newStr(str.size(),''); 

    for(int i=0; i<str.size(); ++i){
        newStr[i] = str[i] ^ key;
    }
    return newStr;
}

//Return the Single Byte XOR key via Bruteforce
char CryptoLib::singleByteXOR_Bruteforce_key(string cipherBlock)
{
    char key = 0;
    int maxCount=0;
    string decodedMessage;

    //Brute force all 256 possibilities
    for(int i=0; i<=256; i++)
    {
        char ch = (char) i;

        //Perform Single Byte XOR -- modified version
        string attempt = singleByteXOR_V2(cipherBlock, ch);

        // cout << "Message: " << attempt << endl;

        int count = 0;
        /*
            Look for characters that are alphabetic and the space character,
            if it finds, increment the counter
        */
        for(int j=0; j<attempt.size(); j++)
        {
            if((attempt[j] >= 65 && attempt[j] <= 122) || attempt[j] == ' ')
            {
                count++;
            }
        }

        //The one with the highest count, has the predicted key
        if(count > maxCount)
        {
            maxCount = count;
            key = ch;
            // decrypted = attempt;
        }
    }

    // cout << "KEY: " << key << endl;
    // cout << "MESSAGE: " << decrypted << endl;

    return key;
}

//Guess Key length of the cipher
int CryptoLib::guess_key_length(string cipherText)
{
    int KEYSIZE = -1;
    double leastNormalized = INT_MAX;

    //Guess a keysize from 2 to 40
    for(int i=2; i<=40; i++)
    {
        double normalize = 0.0f;

        //Number of bytes per key size
        int bytes = cipherText.size()/i;

        for(int j=0; j<bytes; j++)
        {
            string blockA = cipherText.substr((j*i), i);
            string blockB = cipherText.substr(((j+1)*i), i);

            //Calculate Hamming Distance between 2 strings
            int edit_distance = hamming_distance(blockA, blockB);

            normalize += ((double)edit_distance)/((double)blockA.size());
        }

        //Now, take an average 
        normalize /= bytes;

        //The key size that has the least edit distance is the key size required
        if(normalize > 0 && normalize < leastNormalized)
        {
            leastNormalized = normalize;
            KEYSIZE = i;
        }
    }

    //Return the key size
    return KEYSIZE;
}

Final code:

//The Cryptopals Crypto Challenges - Set 1 Challenge 6
#include "crypto.h"

int main()
{
    CryptoLib crypt;
    string message;
    string binary;
    string key;

    //if this returns 37, then the function is working correct!
    // cout << crypt.hamming_distance("this is a test", "wokka wokka!!!") << endl;

    //Read the file content
    ifstream infile;

    //Converted the B64 text to Hexadecimals through an online converter
    //as it wasn't accurate with b64 decoder that I'd built
    infile.open("message.txt");
    getline(infile, message, '');
    infile.close();

    //Convert the hexadecimal string to ASCII
    message = crypt.con_hex_2_ascii(message);

    //Guess the length of the key
    int keyLength = crypt.guess_key_length(message);

    //Transpose the message based on keysize length
    int blocks = message.size() / keyLength;

    for(int i=0; i<keyLength; ++i)
    {
        string block;
        char indexKey='';

        /*
            Transpose the message into blocks 
            based on keysize and concatenate it 
            into one string
        */
        for(int j=0; j<blocks; j++){
            block += message.substr((j*keyLength) + i,1);
        }

        //Concatenate the selected characters, which will become the predicted key
        key += crypt.singleByteXOR_Bruteforce_key(block);
    }

    cout << "KEY: " << key << endl;
    cout << "DECODED: " << crypt.con_hex_2_ascii(crypt.repeatingKeyXOR(message, 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.

When the following code is executed, the most probable KEYSIZE is 29 and after transposing the message and decrypting the blocks, you get a key of that length:

Terminator X: Bring the noise

Lastly, use the Repeating-Key XOR method to decrypt the message with the cracked key (which looks like lyrics to some music track!):

A rockin' on the mike while the fly girls yell
Well that's my DJ Deshay cuttin' all them Z's
Vanilla's on the mike, man I'm not lazy. ?I'm lettin' my drug kick in
To just let it flow, let my concepts go
And if you don't give a damn, then
So get off 'cause I control the stage
I'm in my own phase
And I can dance better than any kid n' play ?
Stage 2 -- Yea the one ya' wanna listen to
So I can funk it up and make it sound good
For good luck, I like my rhymes atrocious
I'm an effect and that you can bet
There's no denyin', You can try to hang 
Over and over, practice makes perfect
Soon -- Oh my God, homebody, you probably eat
Intoxicating so you stagger like a wino
Vanilla Ice is sellin' and you people are buyin'
Movin' and groovin' trying to sing along
Now you're amazed by the VIP posse. ?
Steppin' so hard like a German Nazi
There's no trippin' on mine, I'm just gettin' down
You trapped me once and I thought that
So step down and lend me your ear 
Your body's gettin' hot, so, so I can smell it
'Cause the lyrics belong to ICE, You can call me Dad 
Let the witch doctor, Ice, do the dance to cure 
You wanna battle me -- Anytime, anywhere ?
You thought that I was weak, Boy, you're dead wrong 
play that funky music Go white boy, go white boy, go
Play that funky music white boy you say it, say it 
Play that funky music, white boy Come on, Come on, Come on

As mentioned above, this was really challenging and fun, at the same time. Although, Most people (academically) know "how-to" break a Repeating-Key XOR (Vignere Cipher) but being able to break it, is another thing.

Hope you liked reading this article!

But, hang in there, surprisingly, this code will be useful later on for many problems.

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!