AES Algoritması Nasıl Çalışıyor ? Birlikte Gerçekleyelim – 1

Tarihçe

Matematik temelli yaklaşımlara sahip bir protokol, görece modern teknolojiler veyahut bir cihazın içerisinde koşan yazılım modüllerine bakıldığında ilgili yaklaşımın yıllar öncesinde bir standarta bindirildiğini görmek çokta zor olmasa gerek. AES’e gebe kalınmadan önce DES(Data Encryption Standart) kullanılmaktaymış. Ancak bu standart numerik olarak düşük şifreleme anahtar boyutuna sahip olduğu için(sadece 56-bit) düzenlenen DES Challenge 3’de 22 saatte DES tarafından şifrelenmiş bir metin kırılabilmiş. Bunun üzerine NIST (National Institute of Standards and Technology) 1997 yılında bir çağrıya çıkıyor. Bu çağrı sonucunda toplanan yaklaşımlardan bazıları gereksinimleri karşılamıyor ve 5 yaklaşım 1999 yılında bir nevi final sahnesine çıkıyor. 2000 yılında Rijndael isimli kişinin yaklaşımı 1.sıraya yükseliyor ve 2001 yılında bu yaklaşım standart haline getiriliyor. Ortaya DES’den daha hızlı çalışan, farklı şifreleme anahtar boyutuna(128, 192, 256) sahip bir şifreleme algoritması meydana geliyor.

Hakkında

  • Bu algoritma 128, 192, 256 bit şifreleme anahtar boyutunu desteklemekte. Eğer bir işlemde sizden AES-128 kullanılması talep ediliyorsa, şifreleme anahtar boyutunuz 128bit, AES-192 ise 192bit olmak zorunda.
  • Bu algoritma simetrik bir algoritmadır, simetrik demek şifrelemek ve şifrenin çözülmesi işlemleri aynı şifreleme anahtarı ile yapılıyor demektir. Bir yerde başka bir şifreleme algoritması için asimetrik ifadesine denk gelirseniz, ilgili şifreleme algoritmasında şifreleme ve şifrenin çözülmesi farklı şifreleme anahtarı ile yapılmakta.
  • Şifreleme blok blok yapılmakta. Her blok boyutu 128bit olarak alınmaktadır.

Terminolojik İfadeler

  • Block Chiper : Şifreleme yapılırken kullanılan yöntemde bit bit değil blok blok bir şifreleme yapılıyorsa kullanılan terimdir.
  • Plaintext : Şifreleme yapılacak ifadedir.
  • Key : Şifreleme yapılırken kullanılacak şifreleme anahtarı olarak kullanılacak ifadedir.
  • Round : Şifreleme sürecinde yapılan iterasyon sayısı. Key boyutuna göre değişiklik göstermektedir. 128 için 10 round, 192 için 12 round, 256 için 14 round yapılmaktadır. Bazı kaynaklarda sırasıyla 11, 13, 15 şeklinde görülebilir. İlk round verilen key ile aynı ifade ile sonuçlandığı için.
  • Round Key : Her round sonrasında, ilgili round için toplamda 128bit uzunluğunda her biri 4byte uzunluğuna sahip 4 farklı subkey oluşturulur. Matematiksel ifadesi ‘w’ olarak görebilirsiniz. İlk round sonucunda elde edilen round key ifadesi, sisteme verilen key ile aynı değere sahiptir.
  • Substitution Box (S-Box) : Şifreleme yapılırken kullanılan look-up tablosudur. Forward ve Inverse S-Box olarak 2 farklı tablo mevcuttur.
  • Round Constant : İlgili round’ın numerik değerine göre daha önceden hesaplanmış sabit ifadedir. Look-up tablosu üzerinden değerler alınabilir. Detaylarını göreceğiz.
  • State : Şifrelenecek 4×4’lük 16 byte içeren bir bloktur.
  • Chipher Text : Şifrelenmiş metin.

Şifreleme Aşamaları

1. Şifreleme Anahtarının Açılımı (Key Expansion)

Bu aşamada orjinal key alınarak, her round sonrasında yeni bir round-key oluşturulur. 128bit key için Round Key oluşturma işleminin adımları şu şekildedir. 192 ve 256 bit bir tık daha komplike olacaktır. Daha öncesinde her round sonrasında 128b round-key oluşturulduğundan ve AES-128 için toplam 11 round-key olduğundan bahsetmiştik. Bu durumda 11 x 128b = 176 byte uzunluğuna sahip bir dizi bizim için yeterli olacaktır.

Tüm seri boyunca kullanacağımız key : “AES BLOG YAZIMIZ” olacaktır. Her karakter bir byte olacak şekilde düşünülmüştür. Bu anahtarımızı hex formatına dönüştürelim;

  1. İlk round sonrasında oluşan round-key(w0, w1, w2, w3) chipker key ile aynı değere sahiptir.

  2. Diğer roundlar hesaplanırken eğer sub round-key 4’ün katı değilse şu formül uygulanır;

    w[ i ] = w[i – 1] ^ w[i – 4]

    Örnek : İkinci round’a ait i = 6 sub round-key hesaplanırken;
    w[6] = w[5] ^ w[2] şeklinde olacaktır.

  3. Eğer i % 4 == 0 ise burada süreç değişecektir.

    1. Öncelike Rotword işlemi yapılır. Bu işlemde w[i -1] değeri bir byte sola kaydırılır. Kaydırma işlemi lineer olarak değil, circular olarak gerçekleştirilir.
    2. Yapılan Rotword işlemi sonrasında elde edilen byte’lar S-BOX tablosuna parametre olarak gönderilir. Ve yeni bir dizi elde edilmiş olur.
    3. Yeni elde edilen dizi, ilgili round’ın numerik değerine ait round sabiti ile xor işlemi tabi tutulur.
    4. Elde edilen son değer ile w(i -4) değeri xor işlemine tabi tutulur.

    Örnek : w[4] sub round-key değerini hesaplamak isteyelim ve elimizde ki w[3] : (20, 46, 75, 67) ve w[0] : (54, 68, 61, 74) olsun.
    Circular Kaydırma : (46, 75, 67, 20) olacaktır.
    Byte Substitution (S – Box) : (B7, 5A, 9D, 85) olacaktır (Yukarda bulunan S-BOX tablosuna gönderilerek dönen değerlerden oluşturuldu).
    Round Sabitinin Eklenmesi : Bu round 1. round olduğu için (2 gibi düşünebilir ancak daha önce belirttiğim gibi ilk round direkt olarak chiper key ile eşleştirildiği için 0. round olarak varsayılmakta.) (01, 00, 00, 00) ^ (B7, 5A, 9D, 85) işleminin sonucu (B6, 5A, 9D, 85) olacaktır.

    Son adım ise w[i – 4], i = 4 için w[0] değeri ile bulduğumuz sonucu xor işlemine tabi tutalım. w[4] : (E2, 32, FC, F1) olacaktır.


Şimdi ise kendi chiper key değerimizden round-key değerlerimizi oluşturmak için gerekli fonksiyonu oluşturalım.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>


#define getSBoxValue(num) (sbox[(num)])
#define KEY_EXP_SIZE 176
#define Swap4Bytes(val) \
 ( (((val) >> 24) & 0x000000FF) | (((val) >>  8) & 0x0000FF00) | \
   (((val) <<  8) & 0x00FF0000) | (((val) << 24) & 0xFF000000) )

uint8_t round_sub_keys[KEY_EXP_SIZE];


static const uint8_t sbox[256] = {
  //0     1    2      3     4    5     6     7      8    9     A      B    C     D     E     F
  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };


  static const uint8_t Rcon[11] = {
  0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };


static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
{
  unsigned i, j, k;
  uint8_t tempa[4]; // Used for the column/row operations
  const uint8_t Nr = 10;
  const uint8_t Nk = 4;
  const uint8_t Nb = 4;

  // The first round key is the key itself.
  for (i = 0; i < Nk; ++i)
  {
    RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
    RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
    RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
    RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
  }

  // All other round keys are found from the previous round keys.
  for (i = Nk; i < Nb * (Nr + 1); ++i)
  {
    {
      k = (i - 1) * 4;
      tempa[0]=RoundKey[k + 0];
      tempa[1]=RoundKey[k + 1];
      tempa[2]=RoundKey[k + 2];
      tempa[3]=RoundKey[k + 3];

    }

    if (i % Nk == 0)
    {
      // This function shifts the 4 bytes in a word to the left once.
      // [a0,a1,a2,a3] becomes [a1,a2,a3,a0]

      // Function RotWord()
      {
        const uint8_t u8tmp = tempa[0];
        tempa[0] = tempa[1];
        tempa[1] = tempa[2];
        tempa[2] = tempa[3];
        tempa[3] = u8tmp;
      }

      // SubWord() is a function that takes a four-byte input word and 
      // applies the S-box to each of the four bytes to produce an output word.

      // Function Subword()
      {
        tempa[0] = getSBoxValue(tempa[0]);
        tempa[1] = getSBoxValue(tempa[1]);
        tempa[2] = getSBoxValue(tempa[2]);
        tempa[3] = getSBoxValue(tempa[3]);
      }

      tempa[0] = tempa[0] ^ Rcon[i/Nk];
    }

    j = i * 4; 
    k = (i - Nk) * 4;
    RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
    RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
    RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
    RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
  }
}

/* Check with this online web-site : https://www.cryptool.org/en/cto/aes-step-by-step */

int main(int argc, char* argv[])
{
    uint8_t chiper_key[16] = {0x41, 0x45, 0x53, 0x20, 0x42, 0x4c, 0x4f, 0x47, 0x20, 0x59, 0x41, 0x5a, 0x49, 0x4d, 0x49, 0x5a};

    KeyExpansion(round_sub_keys, chiper_key);

    for (int i = 0; i < 11; ++i)
    {
        printf("Round {%i} -> ", i);

        for (int y = 0; y < 16; ++y)
        {
            static int sub_key_idx = 0;

            if (y % 4 == 0)
            {
                printf("sub-key-w[%i] :", sub_key_idx);
                ++sub_key_idx;
            }

            printf("%02x ",round_sub_keys[i * 16 + y]);
        }

        printf("\r\n");       

    }
}

Round {0} -> sub-key-w[0] :41 45 53 20 sub-key-w[1] :42 4c 4f 47 sub-key-w[2] :20 59 41 5a sub-key-w[3] :49 4d 49 5a
Round {1} -> sub-key-w[4] :a3 7e ed 1b sub-key-w[5] :e1 32 a2 5c sub-key-w[6] :c1 6b e3 06 sub-key-w[7] :88 26 aa 5c
Round {2} -> sub-key-w[8] :56 d2 a7 df sub-key-w[9] :b7 e0 05 83 sub-key-w[10] :76 8b e6 85 sub-key-w[11] :fe ad 4c d9
Round {3} -> sub-key-w[12] :c7 fb 92 64 sub-key-w[13] :70 1b 97 e7 sub-key-w[14] :06 90 71 62 sub-key-w[15] :f8 3d 3d bb
Round {4} -> sub-key-w[16] :e8 dc 78 25 sub-key-w[17] :98 c7 ef c2 sub-key-w[18] :9e 57 9e a0 sub-key-w[19] :66 6a a3 1b
Round {5} -> sub-key-w[20] :fa d6 d7 16 sub-key-w[21] :62 11 38 d4 sub-key-w[22] :fc 46 a6 74 sub-key-w[23] :9a 2c 05 6f
Round {6} -> sub-key-w[24] :ab bd 7f ae sub-key-w[25] :c9 ac 47 7a sub-key-w[26] :35 ea e1 0e sub-key-w[27] :af c6 e4 61
Round {7} -> sub-key-w[28] :5f d4 90 d7 sub-key-w[29] :96 78 d7 ad sub-key-w[30] :a3 92 36 a3 sub-key-w[31] :0c 54 d2 c2
Round {8} -> sub-key-w[32] :ff 61 b5 29 sub-key-w[33] :69 19 62 84 sub-key-w[34] :ca 8b 54 27 sub-key-w[35] :c6 df 86 e5
Round {9} -> sub-key-w[36] :7a 25 6c 9d sub-key-w[37] :13 3c 0e 19 sub-key-w[38] :d9 b7 5a 3e sub-key-w[39] :1f 68 dc db
Round {10} -> sub-key-w[40] :09 a3 d5 5d sub-key-w[41] :1a 9f db 44 sub-key-w[42] :c3 28 81 7a sub-key-w[43] :dc 40 5d a1

Çıktımız yukarda bulunduğu gibi olacaktır. Çıktının sağlaması sitesi üzerinden doğrulanabilir.

Kaynaklar

Bir Cevap Yazın

Please log in using one of these methods to post your comment:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google fotoğrafı

Google hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s