Cryptography - MixColumns Transformation



The AES (Advanced Encryption Standard) algorithm, which uses the MixColumns transformation, is used for both data encryption and decryption. The AES data matrix's every column is subjected to this mathematical process.

How it works?

For the MixColumns transformation in AES to work properly, each column of the state matrix needs to undergo a mathematical operation. Polynomial arithmetic in GF(28), an original algebraic field called the Galois Field (GF), forms the fundamental component of this operation.

Here is an in−depth description of how it operates −

  • State Matrix Representation − The data being processed is stored in a 4x4 grid called the state matrix.
  • Fixed Matrix − A fixed matrix is used in the MixColumns transformation. This matrix remains same throughout the encryption and decryption procedure.
  • Multiplication Column−wise − Each column of the state matrix is considered a polynomial in GF(2^8). The polynomial is then multiplied by the fixed matrix's corresponding column.
  • Polynomial Multiplication − When multiplying polynomials in GF(2^8), there are a few rules that must be followed. Firstly, modulo arithmetic must be used with a fixed polynomial called the irreducible polynomial. In the case of AES, this polynomial is x8 + x4 + x3 + x + 1 represented in hexadecimal as 0x11B.
  • XOR Operation − Following the multiplication stage, the results are XORed (exclusively ORed) to produce the final result for each column.
  • Resultant State Matrix − By executing the multiplication and XOR operations for every column, the converted state matrix−which shows the MixColumns transformation−is produced.

The data's diffusion and confusion resulting from this method enhance the encryption process' security. By ensuring that modifications to a single byte in the input data affect numerous bytes in the output, it becomes more challenging for attackers to access and decrypt the encrypted data.

Implementation using Python

In order to perform the MixColumns transformation on a state matrix, the Python code implements two helper functions: mix_columns and gf_multiply. The state matrix's columns are converted by combining the bytes in each column with the help of a fixed matrix multiplication at a stage of the AES encryption process called MixColumns.

Example

def mix_columns(state):
   fixed_matrix = [
      [0x02, 0x03, 0x01, 0x01],
      [0x01, 0x02, 0x03, 0x01],
      [0x01, 0x01, 0x02, 0x03],
      [0x03, 0x01, 0x01, 0x02]
   ]

   new_state = []
   for col in range(4):
      new_column = []
      for row in range(4):
         val = 0
         for i in range(4):
            val ^= gf_multiply(fixed_matrix[row][i], state[i][col])
         new_column.append(val)
      new_state.append(new_column)
   return new_state

def gf_multiply(a, b):
   p = 0
   for _ in range(8):
      if b & 1:
         p ^= a
      hi_bit_set = a & 0x80
      a <<= 1
      if hi_bit_set:
         a ^= 0x1B  # irreducible polynomial
      b >>= 1
   return p if p < 0x80 else p ^ 0x11B

# Example usage:
state_matrix = [
   [0x32, 0x88, 0x31, 0xe0],
   [0x43, 0x5a, 0x31, 0x37],
   [0xf6, 0x30, 0x98, 0x07],
   [0xa8, 0x8d, 0xa2, 0x34]
]
new_state = mix_columns(state_matrix)

# Displaying output in matrix form
for row in new_state:
   print(row)

Following is the output of the above example −

Input/Output

[484, 6, 101, 424]
[67, 506, 318, 232]
[11, 322, 214, 421]
[170, 424, 414, 120]

Implementation using Java

The Java implementation's mixColumns function receives a 4x4 state matrix as input and outputs the modified state matrix following the application of the MixColumns transformation. The gfMultiply function is used to perform polynomial multiplication for each matrix element in GF(2^8). So the code using Java is given below −

Example

public class MixColumns {

   public static int[][] mixColumns(int[][] state) {
      int[][] fixedMatrix = {
         {0x02, 0x03, 0x01, 0x01},
         {0x01, 0x02, 0x03, 0x01},
         {0x01, 0x01, 0x02, 0x03},
         {0x03, 0x01, 0x01, 0x02}
      };

      int[][] newState = new int[4][4];
      for (int col = 0; col < 4; col++) {
         for (int row = 0; row < 4; row++) {
            int val = 0;
            for (int i = 0; i < 4; i++) {
               val ^= gfMultiply(fixedMatrix[row][i], state[i][col]);
            }
            newState[row][col] = val;
         }
      }
      return newState;
   }

   public static int gfMultiply(int a, int b) {
      int p = 0;
      for (int i = 0; i < 8; i++) {
         if ((b & 1) != 0) {
            p ^= a;
         }
         int hiBitSet = a & 0x80;
         a <<= 1;
         if (hiBitSet != 0) {
            a ^= 0x1B;  // irreducible polynomial
         }
         b >>= 1;
      }
      return p;
   }

   public static void main(String[] args) {
      int[][] stateMatrix = {
         {0x32, 0x88, 0x31, 0xe0},
         {0x43, 0x5a, 0x31, 0x37},
         {0xf6, 0x30, 0x98, 0x07},
         {0xa8, 0x8d, 0xa2, 0x34}
      };
      int[][] newState = mixColumns(stateMatrix);

      // Displaying output in matrix form
      for (int[] row : newState) {
         for (int val : row) {
            System.out.print(String.format("%02X ", val));
         }
         System.out.println();
      }
   }
}

Following is the output of the above example −

Input/Output

FF 158 0B 1B1 
11D E1 142 B3
65 13E D6 85 
1A8 E8 1A5 163 

Implementation using C++

In this implementations we are going to use C++ and we will have a function called mixColumns which takes a 4x4 state matrix as input and returns the transformed state matrix after using the MixColumns transformation. So the code is as follows −

Example

#include <iostream>
#include <vector>

int gfMultiply(int a, int b);

std::vector<std::vector<int>> mixColumns(std::vector<std::vector<int>> state) {
   std::vector<std::vector<int>> fixedMatrix = {
      {0x02, 0x03, 0x01, 0x01},
      {0x01, 0x02, 0x03, 0x01},
      {0x01, 0x01, 0x02, 0x03},
      {0x03, 0x01, 0x01, 0x02}
   };

   std::vector<std::vector<int>> newState(4, std::vector<int>(4, 0));
   for (int col = 0; col < 4; col++) {
      for (int row = 0; row < 4; row++) {
         int val = 0;
         for (int i = 0; i < 4; i++) {
            val ^= gfMultiply(fixedMatrix[row][i], state[i][col]);
         }
         newState[row][col] = val;
      }
   }
   return newState;
}

int gfMultiply(int a, int b) {
   int p = 0;
   for (int i = 0; i < 8; i++) {
      if (b & 1) {
         p ^= a;
      }
      int hiBitSet = a & 0x80;
      a <<= 1;
      if (hiBitSet) {
         a ^= 0x1B;  // irreducible polynomial
      }
      b >>= 1;
   }
   return p;
}

int main() {
   std::vector<std::vector<int>> stateMatrix = {
      {0x32, 0x88, 0x31, 0xe0},
      {0x43, 0x5a, 0x31, 0x37},
      {0xf6, 0x30, 0x98, 0x07},
      {0xa8, 0x8d, 0xa2, 0x34}
   };
   auto newState = mixColumns(stateMatrix);

   // Displaying output in matrix form
   for (auto row : newState) {
      for (int val : row) {
         std::cout << std::hex << val << " ";
      }
      std::cout << std::endl;
   }
   return 0;
}

Following is the output of the above example −

Input/Output

ff 158 b 1b1 
11d e1 142 b3 
65 13e d6 85 
1a8 e8 1a5 163 

Summary

The MixColumns transformation is an important component of the AES encryption algorithm that enhances the security of data encryption and decryption processes. Using polynomial arithmetic in the GF(2^8) Galois Field, this transformation works on the columns of the state matrix. The provided implementations in Python, Java, and C++ showcase how to programmatically implement the MixColumns transformation.

Advertisements