Skip to main content

C++ Implementation of SAES(Simplified AES) 16bits

S-AES Encryption Procedure



Code:

#include <bits/stdc++.h>
using namespace std;

//Map for S-Box Substituion for Encryption.
unordered_map<stringstringSbox = {
    {"0000""1001"},
    {"0001""0100"},
    {"0010""1010"},
    {"0011""1011"},
    {"0100""1101"},
    {"0101""0001"},
    {"0110""1000"},
    {"0111""0101"},
    {"1000""0110"},
    {"1001""0010"},
    {"1010""0000"},
    {"1011""0011"},
    {"1100""1100"},
    {"1101""1110"},
    {"1110""1111"},
    {"1111""0111"}};

//Map for S-Box Substituion for decryption.
//Inverse of S-box for encrytion.
unordered_map<stringstringSboxInverse = {
    {"1001""0000"},
    {"0100""0001"},
    {"1010""0010"},
    {"1011""0011"},
    {"1101""0100"},
    {"0111""0101"},
    {"1000""0110"},
    {"0101""0111"},
    {"0110""1000"},
    {"0010""1001"},
    {"0000""1010"},
    {"0011""1011"},
    {"1100""1100"},
    {"1110""1101"},
    {"1111""1110"},
    {"0111""1111"}};

//Matrix for Polynomial Reduction in encryption
int Smatrix[2][2] = {{14}, {41}};

//Matrix for Polynomial Reduction in decryption
int InverseSmatrix[2][2] = {{92}, {29}};

//4 bit binary=X^4+X+1 is polynomial irreducible
vector<intirreducible = {10011};

//Exchange 1st and 2nd nibble.
//e.g. 1101 1001 => 1001 1101
void RotateNibble(vector<int&W)
{
    int n = W.size();
    int temp;

    for (int i = 0i < 4i++)
    {
        temp = W[i];
        W[i] = W[i + 4];
        W[i + 4] = temp;
    }
}

//Exchange 2nd and 4th nibble.
//e.g. 1001 1101 1110 0011 => 1001 0011 1110 1101
void ShiftRow(vector<int&W)
{
    int temp;
    for (int i = 4i < 8i++)
    {
        temp = W[i];
        W[i] = W[i + 8];
        W[i + 8] = temp;
    }
}

//Substitues values of S-box with given nibbles.
void SubNibble(vector<int&w)
{
    int n = w.size();

    for (int i = 0i < n / 4i++)
    {
        //converting the nibble to string as map is of string.
        string temp = "";
        for (int j = 4 * ij < 4 * (i + 1); j++)
        {
            temp += to_string(w[j]);
        }

        //Substituting the Sbox value
        temp = Sbox[temp];

        //replacing with original nibble.
        for (int j = 4 * ij < 4 * (i + 1); j++)
        {
            w[j] = (int)temp[j % 4] - 48;
        }
    }
}

//Substitues values of InverseS-box with given nibbles.
void InverseSubNibble(vector<int&w)
{
    int n = w.size();

    for (int i = 0i < n / 4i++)
    {
        //converting the nibble to string as map is of string.
        string temp = "";
        for (int j = 4 * ij < 4 * (i + 1); j++)
        {
            temp += to_string(w[j]);
        }

        //Substituting the InverseSbox value
        temp = SboxInverse[temp];

        //replacing with original nibble.
        for (int j = 4 * ij < 4 * (i + 1); j++)
        {
            w[j] = (int)temp[j % 4] - 48;
        }
    }
}

//Convert binary string to decimal.
int BinaryToDecimal(string s)
{
    int value = stoull(s02);

    return value;
}

//returns binary value in terms of vector from decimal value.
vector<intDecimalToBinary(int n)
{
    //vector to store binary bits.
    vector<intbinary;

    //converting decimal to binary.
    while (n > 0)
    {
        binary.push_back(n % 2);
        n = n / 2;
    }

    // reversing the vector as it stores the binary value in reverse.
    reverse(binary.begin(), binary.end());

    //if length is less than four converting it to 4 bit binary by adding zeros at front.
    if (binary.size() == 2)
    {
        binary.insert(binary.begin(), 0);
        binary.insert(binary.begin(), 0);
    }

    else if (binary.size() == 3)
        binary.insert(binary.begin(), 0);

    return binary;
}

//Reduce the given value to four bit binary using polynomial irreducible.
int polynomialReducer(int value)
{
    //If value is less than 16 means it is already four bit so return same value;
    if (value < 16)
        return value;

    //condition where we get two X^3 while reducing so we 
    //cannot solve using XOR operation so directly returning the value.
    if (value == 135)
        return 14;

    //binary value of given decimal value.
    vector<intreduceMe = DecimalToBinary(value);

    //Reducing the decimal value to 4bit binary
    while (reduceMe.size() > 4)
    {
        for (int i = 0i < 5i++)
        {
            //XOR with polynomial irreducible.
            reduceMe[i] = reduceMe[i] ^ irreducible[i];
        }

        while (reduceMe[0] == 0)
        {
            //Removing all MSB zeros.
            reduceMe.erase(reduceMe.begin());
        }
    }

    //converting the reduced value to binary string.
    string temp = "";
    for (int i = 0i < reduceMe.size(); i++)
    {
        temp += to_string(reduceMe[i]);
    }

    //returning the reduced decimal value.
    return BinaryToDecimal(temp);
}

//Function to perform mixcolumn operation in encryption.
void MixColumn(vector<int&plain)
{
    //Matrix for plaintext message. First two nibbles become first column 
    //and remaining two become second column.
    int plainmatrix[2][2] = {{00}, {00}};
    //Matrix to store the values after multiplication of plainmatrix with Smatrix.
    int multiplied[2][2] = {{00}, {00}};

    //Converting all nibble(4-bit) to decimal and storing it to plainMatrix.
    int nibble = 0;
    for (int i = 0i < 2i++)
    {
        for (int j = 0j < 2j++)
        {
            string temp = "";
            for (int k = 4 * nibblek < 4 * (nibble + 1); k++)
            {
                temp += to_string(plain[k]);
            }

            plainmatrix[j][i] = BinaryToDecimal(temp);
            nibble++;
        }
    }

    //Multiplication of plainmatrix with SMatrix.
    for (int i = 0i < 2i++)
    {
        for (int j = 0j < 2j++)
        {
            //Storing multiplied value and also passing it to polynomialReducer to 
            //reduce it to 4-bit binary.
            multiplied[i][j] = (polynomialReducer(Smatrix[i][0] * plainmatrix[0][j])) 
                ^ (polynomialReducer(Smatrix[i][1] * plainmatrix[1][j]));
        }
    }

    //start with first nibble
    nibble = 0;
    for (int i = 0i < 2i++)
    {
        for (int j = 0j < 2j++)
        {
            //converting the decimal value to binary and storing it to vector temp;
            vector<inttemp;
            temp = DecimalToBinary(multiplied[j][i]);

            // Replacing the resultant mixcolumn value with original value in plaintext;
            for (int k = 4 * nibblek < 4 * (nibble + 1); k++)
            {
                plain[k] = temp[k % 4];
            }
            //next nibble.
            nibble++;
        }
    }
}

//Function to perform mixcolumn operation in decryption.
void InverseMixColumn(vector<int&cipher)
{
    //Matrix for ciphertext message. First two nibbles become first column and 
    //remaining two become second column.
    int ciphermatrix[2][2] = {{00}, {00}};
    //Matrix to store the values after multiplication of ciphermatrix with Smatrix.
    int multiplied1[2][2] = {{00}, {00}};

    //Converting all nibble(4-bit) to decimal and storing it to cipherMatrix.
    int nibble = 0;
    for (int i = 0i < 2i++)
    {
        for (int j = 0j < 2j++)
        {
            string temp = "";
            for (int k = 4 * nibblek < 4 * (nibble + 1); k++)
            {
                temp += to_string(cipher[k]);
            }

            ciphermatrix[j][i] = BinaryToDecimal(temp);
            nibble++;
        }
    }

    //Multiplication of ciphermatrix with SMatrix.
    for (int i = 0i < 2i++)
    {
        for (int j = 0j < 2j++)
        {
            //Storing multiplied value and also passing it to polynomialReducer to 
            //reduce it to 4-bit binary.
            multiplied1[i][j] = (polynomialReducer(InverseSmatrix[i][0] * ciphermatrix[0][j])) 
            ^ (polynomialReducer(InverseSmatrix[i][1] * ciphermatrix[1][j]));
        }
    }

    //start with first nibble
    nibble = 0;
    for (int i = 0i < 2i++)
    {
        //converting the decimal value to binary and storing it to vector temp;
        for (int j = 0j < 2j++)
        {
            //converting the decimal value to binary and storing it to vector temp;
            vector<inttemp;
            temp = DecimalToBinary(multiplied1[j][i]);

            // Replacing the resultant mixcolumn value with original value in ciphertext;
            for (int k = 4 * nibblek < 4 * (nibble + 1); k++)
            {
                cipher[k] = temp[k % 4];
            }
            //next nibble.
            nibble++;
        }
    }
}


//Key generation for encryption.
//There are total three keys key1,key2,key3.
void keyGeneration(vector<int&key,vector<int&key1,vector<int&key2,vector<int&key3)
{
    //declaring w0 and w1 for key1;
    vector<intw0(80);
    vector<intw1(80);
    
    //w0 is first eight bits of original key and w1 is last eight bits of original key.
    for (int i = 0i < 8i++)
    {
        w0[i] = key[i];
        w1[i] = key[i + 8];
    }

    //key1 is concatenation of w0 andd w1.
    for (int i = 0i < 8i++)
    {
        key1[i] = w0[i];
        key1[i + 8] = w1[i];
    }

    //Printing key1
    cout << "\nKEY1 :";
    for (int i = 0i < 16i++)
    {
        cout << key1[i] << " ";
    }

    //for calculating w2 we perform following operations
    //w2 = w0 XOR 10000000 XOR SubstituteNibble(RotateNibble(w1))
    //temp1 is w0 XOR 10000000
    //temp2 is SubstituteNibble(RotateNibble(w1))
    //xorwith1 is 10000000
    //declaring w2 and two temporary vectors for
    vector<intw2(160);
    vector<inttemp1(80);
    vector<inttemp2(80);
    vector<intxorwith1 = {10000000};

    //storing value of w1 to temp2
    for (int i = 0i < 8i++)
    {
        temp2[i] = w1[i];
    }

    //Rotating nibble of temp2 i.e.w1
    RotateNibble(temp2);
    //Substituting nibble of temp2 i.e.w1
    SubNibble(temp2);

    //performing w0 XOR 10000000
    for (int i = 0i < 8i++)
    {
        temp1[i] = w0[i] ^ xorwith1[i];
    }

    //performing w0 XOR 10000000 XOR SubstituteNibble(RotateNibble(w1)).
    for (int i = 0i < 8i++)
    {
        w2[i] = temp1[i] ^ temp2[i];
    }

    //w3 is XOR operation of w1 and w2.
    vector<intw3(80);

    for (int i = 0i < 8i++)
    {
        w3[i] = w2[i] ^ w1[i];
    }

    //declaring w4 and xorwith 2;
    //for calculating w4 we perform operations same as w2
    //w4 = w2 XOR 00110000 XOR SubstituteNibble(RotateNibble(w3)).
    vector<intw4(80);
    vector<intxorwith2 = {00110000};

    for (int i = 0i < 8i++)
    {
        temp2[i] = w3[i];
    }

    RotateNibble(temp2);
    SubNibble(temp2);

    for (int i = 0i < 8i++)
    {
        temp1[i] = w2[i] ^ xorwith2[i];
    }

    for (int i = 0i < 8i++)
    {
        w4[i] = temp1[i] ^ temp2[i];
    }

    //Calculating w5
    //w5 = w4 XOR w3.
    vector<intw5(80);

    for (int i = 0i < 8i++)
    {
        w5[i] = w4[i] ^ w3[i];
    }

    //Key2 is concatenation of w2 and w3
    for (int i = 0i < 8i++)
    {
        key2[i] = w2[i];
        key2[i + 8] = w3[i];
    }

    //Printing key2
    cout << "\nKEY2 :";
    for (int i = 0i < 16i++)
    {
        cout << key2[i] << " ";
    }

    //Key2 is concatenation of w4 and w5
    for (int i = 0i < 8i++)
    {
        key3[i] = w4[i];
        key3[i + 8] = w5[i];
    }

    //Printing key3
    cout << "\nKEY3 :";
    for (int i = 0i < 16i++)
    {
        cout << key3[i] << " ";
    }
}

void encryption(vector<intkey1,vector<intkey2,vector<intkey3,vector<int&plaintext)
{
    //Encryption shown as in diagram.
    //Performing Add Round key1
    for(int i=0;i<16;i++)
    {
        plaintext[i] = plaintext[i] ^ key1[i];
    }

    //Substitute nibble
    SubNibble(plaintext);
    //Shift row
    ShiftRow(plaintext);
    //mixcolunm operation
    MixColumn(plaintext);

    //Performing Add Round key2
    for(int i=0;i<16;i++)
    {
        plaintext[i] = plaintext[i] ^ key2[i];
    }
    SubNibble(plaintext);
    ShiftRow(plaintext);

    //Performing Add Round key3
    for(int i=0;i<16;i++)
    {
        plaintext[i] = plaintext[i] ^ key3[i];
    }

    //Printing Ciphertext
    cout << "\nCipher Text : ";
    for(int i=0;i<16;i++)
    {
        cout << plaintext[i] << ends;
    }
}

void decryption(vector<intkey1,vector<intkey2,vector<intkey3,vector<int&ciphertext)
{
    //Decryption is exactly opposite of encryption

    ////Performing Add Round key3
    for(int i=0;i<16;i++)
    {
        ciphertext[i] = ciphertext[i] ^ key3[i];
    }

    //Shift row operation
    ShiftRow(ciphertext);
    //Inverse Substitute Nibble
    InverseSubNibble(ciphertext);

    //Performing Add Round key2
    for(int i=0;i<16;i++)
    {
        ciphertext[i] = ciphertext[i] ^ key2[i];
    }

    //Inverse mix column
    InverseMixColumn(ciphertext);
    //Shift row operation
    ShiftRow(ciphertext);
    //Inverse Substitute Nibble
    InverseSubNibble(ciphertext);

    //Performing Add Round key1
    for(int i=0;i<16;i++)
    {
        ciphertext[i] = ciphertext[i] ^ key1[i];
    }

    //Printing Decrypted Message
    cout << "\nDecrypted Message : ";
    for(int i=0;i<16;i++)
    {
        cout << ciphertext[i] << ends;
    }
}


int main()
{
    //Plaintext message
    vector<intplaintext = {1101011100101000};
    //Input Key
    vector<intkey = {0100101011110101};

    //Three keys for encryption initialized it to zeros.
    vector<intkey1(16,0);
    vector<intkey2(16,0);
    vector<intkey3(16,0);

    //Performing keyGeneration, it will return key1, key2, key3
    keyGeneration(key,key1,key2,key3);

    //Copying the plaintext message to ciphertext
    vector<intciphertext(16,0);
    ciphertext = plaintext;

    //encryption, input plaintext, prints ciphertext(encrypted message).
    encryption(key1,key2,key3,ciphertext);
    //decryption, input ciphertext, prints decrypted message(original message).
    decryption(key1,key2,key3,ciphertext);
}

Result:

KEY1 :0 1 0 0 1 0 1 0 1 1 1 1 0 1 0 1

KEY2 :1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 0

KEY3 :1 0 0 0 0 1 1 1 1 0 1 0 1 1 1 1

Cipher Text : 0 0 1 0 0 1 0 0 1 1 1 0 1 1 0 0

Decrypted Message : 1 1 0 1 0 1 1 1 0 0 1 0 1 0 0 0

Comments

Popular posts from this blog

Decompilers Ethical or Non-ethical?

What are decompilers?     A computer program that creates a high-level source file by taking an executable file as input so that it can be recompiled successfully is known as a decompiler. In simple words, a decompiler is the opposite of a compiler which takes a source file and makes it an executable file. A decompiler aims to get the source back from the binary so we can also call it an ant compiler. Though decompilers are an important tool in the reverse engineering of computer software; many times they are unable to perfectly reconstruct the source code. Decompilers misconception or hypothesis?      Decompilation is often classified into 2 classes, the primary being once source code retrieval is required and also the second class being once the whole original source code recovery isn't needed however the goal is to grasp elements of the source code or the complete during a high-level language like C. because the compiler removes data once it will its work thu...