1. С.Г. Баричев, В.В. Гончаров, Р.Е. Серов, Основы современной криптографии, 2-е издание, Москва, "Горячая линия - Телеком", 2002.
2. Осипенко Л. П., Васильченко А. А. Математические основы криптологии. Методические указания для выполнения курсовой работы. – Краснодар: Изд-во КубГТУ, 2009.
3. Кнут Д. Искусство программирования. Т. 2. Получисленные алгоритмы. третье издание. М.: МЦНМО, 1999.
4. http://ru.wikipedia.org/wiki/Rijndael
5. http://kavayii.blogspot.com/2010/02/advanced-encryption-standard-aes-2-aes.html
6. http://book.itep.ru/6/aes.htm
7. http://ru.wikipedia.org/wiki/Конечное_поле
8. http://www.pm298.ru/mgroup.php
9. http://ru.wikipedia.org/wiki/Поле_(алгебра)
Приложение А
Рисунок 5 – Скриншот программы
Приложение Б
Листинг программы
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace CryptoAES
{
public partial class Form1: Form
{
public Form1()
{
InitializeComponent();
}
//public static string[,] Tabl;
public static string ByteToHex(byte a)
{
string hex="";
int b = a / 16;
int c = a % 16;
switch (b)
{
case 0:
hex += '0';
break;
case 1:
hex += '1';
break;
case 2:
hex += '2';
break;
case 3:
hex += '3';
break;
case 4:
hex += '4';
break;
case 5:
hex += '5';
break;
case 6:
hex += '6';
break;
case 7:
hex += '7';
break;
case 8:
hex += '8';
break;
case 9:
hex += '9';
break;
case 10:
hex += 'A';
break;
case 11:
hex += 'B';
break;
case 12:
hex += 'C';
break;
case 13:
hex += 'D';
break;
case 14:
hex += 'E';
break;
case 15:
hex += 'F';
break;
}
switch (c)
{
case 0:
hex += '0';
break;
case 1:
hex += '1';
break;
case 2:
hex += '2';
break;
case 3:
hex += '3';
break;
case 4:
hex += '4';
break;
case 5:
hex += '5';
break;
case 6:
hex += '6';
break;
case 7:
hex += '7';
break;
case 8:
hex += '8';
break;
case 9:
hex += '9';
break;
case 10:
hex += 'A';
break;
case 11:
hex += 'B';
break;
case 12:
hex += 'C';
break;
case 13:
hex += 'D';
break;
case 14:
hex += 'E';
break;
case 15:
hex += 'F';
break;
}
return hex;
}
public static byte HexToByte(string hex)
{
byte a=0;
switch (hex[1])
{
case '0':
a = 0;
break;
case '1':
a = 1;
break;
case '2':
a = 2;
break;
case '3':
a = 3;
break;
case '4':
a = 4;
break;
case '5':
a = 5;
break;
case '6':
a = 6;
break;
case '7':
a = 7;
break;
case '8':
a = 8;
break;
case '9':
a = 9;
break;
case 'A':
a = 10;
break;
case 'B':
a = 11;
break;
case 'C':
a = 12;
break;
case 'D':
a = 13;
break;
case 'E':
a = 14;
break;
case 'F':
a = 15;
break;
}
switch (hex[0])
{
case '0':
a += 0;
break;
case '1':
a += 16;
break;
case '2':
a += 32;
break;
case '3':
a += 48;
break;
case '4':
a += 64;
break;
case '5':
a += 80;
break;
case '6':
a += 96;
break;
case '7':
a += 112;
break;
case '8':
a += 128;
break;
case '9':
a += 144;
break;
case 'A':
a += 160;
break;
case 'B':
a += 176;
break;
case 'C':
a += 192;
break;
case 'D':
a += 208;
break;
case 'E':
a += 224;
break;
case 'F':
a += 240;
break;
}
return a;
}
private void button1_Click(object sender, EventArgs e)
{
byte[] input;
if (richTextBox1.Text.Length%16==0)
input = new byte[richTextBox1.Text.Length];
else
input = new byte[((richTextBox1.Text.Length/16)+1)*16];
for (int i = 0; i < richTextBox1.Text.Length; i++)
input[i] = Convert.ToByte(richTextBox1.Text[i]);
for (int i = richTextBox1.Text.Length; i < input.Length; i++)
input[i] = 0;
//------------------------------------
byte[] key = new byte[1];
if (textBox1.Text.Length <= 16)
key = new byte[16];
if (textBox1.Text.Length > 16 && textBox1.Text.Length <=24)
key = new byte[24];
if (textBox1.Text.Length > 24)
key = new byte[32];
for (int i = 0; i < textBox1.Text.Length; i++)
key[i] = Convert.ToByte(textBox1.Text[i]);
for (int i = textBox1.Text.Length; i < key.Length; i++)
key[i] = 0;
//------------------------------------
AES.Encrypt(ref input, key);
/*TablLeng.ColumnCount = 16;
TablLeng.RowCount = 16;
for (int q = 0; q <= 15; q++)
{
TablLeng.Columns[q].Width = 40;
TablLeng.Columns[q].Name = Convert.ToString(q);
}
int oi = 0;
for (int l = 0; l < 16; l++)
{
for (int q = 0; q < 16; q++)
{
TablLeng[q, l].Value = Tabl[q, l];
oi++;
}
}*/
string txt="";
string[] HexTable = new string[256];
for (int i = 0; i < 256; i++)
{
HexTable[i] = ByteToHex(Convert.ToByte(i));
}
for (int i = 0; i < input.Length; i++)
{
txt += HexTable[input[i]];
}
richTextBox2.Text = txt;
}
private void button2_Click(object sender, EventArgs e)
{
byte[] input = new byte[richTextBox2.Text.Length/2];
string txt="";
for (int i = 0; i < richTextBox2.Text.Length; i+=2)
{
txt=Convert.ToString(richTextBox2.Text[i])+Convert.ToString(richTextBox2.Text[i+1]);
input[i/2] = HexToByte(txt);
}
//------------------------------------
byte[] key = new byte[1];
if (textBox1.Text.Length <= 16)
key = new byte[16];
if (textBox1.Text.Length > 16 && textBox1.Text.Length <= 24)
key = new byte[24];
if (textBox1.Text.Length > 24)
key = new byte[32];
for (int i = 0; i < textBox1.Text.Length; i++)
key[i] = Convert.ToByte(textBox1.Text[i]);
for (int i = textBox1.Text.Length; i < key.Length; i++)
key[i] = 0;
//------------------------------------
AES.Decrypt(ref input, key);
/*TablLeng.ColumnCount = 16;
TablLeng.RowCount = 16;
for (int q = 0; q <= 15; q++)
{
TablLeng.Columns[q].Width = 40;
TablLeng.Columns[q].Name = Convert.ToString(q);
}
int oi = 0;
for (int l = 0; l < 16; l++)
{
for (int q = 0; q < 16; q++)
{
TablLeng[q, l].Value = Tabl[q, l];
oi++;
}
}*/
txt = "";
for (int i = 0; i < input.Length; i++)
txt += Convert.ToChar(input[i]);
richTextBox1.Text = txt;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text.Length <= 16)
label4.Text = "- 128 бит";
if (textBox1.Text.Length > 16 && textBox1.Text.Length <= 24)
label4.Text = "- 192 бит";
if (textBox1.Text.Length > 24)
label4.Text = "- 256 бит";
}
}
class AES
{
#region Create S-Box or InvS-Box
private static void Create_InvSBox(ref byte[] InvSBox)
{
byte[] SBox = new byte[256];
for (int i = 0; i <= 255; i++)
{
byte result = Convert.ToByte(i);
for (int q = 1; q < 7; q++)
result = AES.PolynomsMult(AES.PolynomsMult(result, result, 0x11b), Convert.ToByte(i), 0x11b);
result = AES.PolynomsMult(result, result, 0x11b);
result = AES.PolynomsMult(0x1f, result, 0x101);
SBox[i] = Convert.ToByte(result ^ 0x63);
}
for (int i = 0; i <= 255; i++)
{
InvSBox[SBox[i]] = Convert.ToByte(i);
}
}
private static void Create_SBox(ref byte[] SBox)
{
for (int i = 0; i <= 255; i++)
{
byte result = Convert.ToByte(i);
for (int q = 1; q < 7; q++)
result = AES.PolynomsMult(AES.PolynomsMult(result, result, 0x11b), Convert.ToByte(i), 0x11b);
result = AES.PolynomsMult(result, result, 0x11b);
result = AES.PolynomsMult(0x1f, result, 0x101);
SBox[i] = Convert.ToByte(result ^ 0x63);
}
}
#endregion
#region Multiply Polynoms
private static byte PolynomsMult(byte a, byte b, ushort mod)
{
ushort mult = 0;
ushort temp = b;
while (a > 0)
{
if ((a & 0x01) == 1) mult ^= temp;
a >>= 1;
temp <<= 1;
}
for (byte i = 14; i >= 8; i--)
if ((mult >> i) == 1) mult = Convert.ToUInt16(mult ^ (mod << (i - 8)));
return Convert.ToByte(mult);
}
#endregion
#region Key schedule
private static byte[,] KeyExpansion(byte[] key, byte[] SBox)
{
byte[] RCon= new byte[] { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
byte[,] AKey = new byte[4,60];
for (int i = 0; i < 60; i++)
{
for (int q = 0; q < 4; q++)
AKey[q, i] = 0;
}
if (key.Length == 16)
{
AKey = new byte[4, 44];
byte ch = 0;
for (int i = 0; i < 4; i++)
{
for (int q = 0; q < 4; q++)
{
AKey[i, q] = key[ch];
ch++;
}
}
for (int i = 4; i < 44; i++)
{
byte[] temp = new byte[4];
for (int q = 0; q < 4; q++)
{
temp[q] = AKey[q, i - 1];
}
if ((i % 4) == 0)
{
temp = SubWord(RotWord(temp), SBox);
temp[0] ^= RCon[(i / 4) - 1];
}
for (int q = 0; q < 4; q++)
AKey[q, i] = Convert.ToByte(AKey[q, i - 4] ^ temp[q]);
}
}
if (key.Length == 24)
{
AKey = new byte[4, 52];
byte ch = 0;
for (int i = 0; i < 4; i++)
{
for (int q = 0; q < 6; q++)
{
AKey[i, q] = key[ch];
ch++;
}
}
for (int i = 6; i < 52; i++)
{
byte[] temp = new byte[4];
for (int q = 0; q < 4; q++)
{
temp[q] = AKey[q, i - 1];
}
if ((i % 6) == 0)
{
temp = SubWord(RotWord(temp), SBox);
for (int q = 0; q < 4; q++)
{
temp[q] ^= RCon[q];
}
}
else if (i % 6 == 3)
{
temp = SubWord(temp, SBox);
}
for (int q = 0; q < 4; q++)
AKey[q, i] = Convert.ToByte(AKey[q, i - 6] ^ temp[q]);
}
}
if (key.Length == 32)
{
AKey = new byte[4, 60];
byte ch = 0;
for (int i = 0; i < 4; i++)
{
for (int q = 0; q < 8; q++)
{
AKey[i, q] = key[ch];
ch++;
}
}
for (int i = 8; i < 60; i++)
{
byte[] temp = new byte[4];
for (int q = 0; q < 4; q++)
{
temp[q] = AKey[q, i - 1];
}
if ((i % 8) == 0)
{
temp = SubWord(RotWord(temp), SBox);
for (int q = 0; q < 4; q++)
{
temp[q] ^= RCon[q];
}
}
else if (i % 8 == 4)
{
temp = SubWord(temp,SBox);
}
for (int q=0; q<4; q++)
AKey[q,i] = Convert.ToByte(AKey[q,i - 8] ^ temp[q]);
}
}
return AKey;
}
private static byte[] SubWord(byte[] W, byte[] SBox)
{
byte[] temp = new byte[4];
for (int i = 0; i < 4; i++)
temp[i] = SBox[W[i]];
return temp;
}
private static byte[] RotWord(byte[] W)
{
byte[] temp = new byte[4];
for (int i = 0; i < 4; i++)
temp[i] = W[(i + 1)%4];
return temp;
}
#endregion
#region Block_Encrypt or Block_Decrypt
private static void Cipher(ref byte[,] state, byte[,] AKey, byte[] SBox, byte length)
{
AddRoundKey(ref state, AKey, 0);
for (int round = 1; round <= 9+length*2; round++)
{
SubBytes(ref state, SBox);
ShiftRows(ref state);
MixColumns(ref state);
AddRoundKey(ref state, AKey, round*4);
}
SubBytes(ref state,SBox);
ShiftRows(ref state);
AddRoundKey(ref state, AKey, 40+length*8);
}
private static void InvCipher(ref byte[,] state, byte[,] AKey, byte[] InvSBox, byte length)
{
AddRoundKey(ref state, AKey, 40 + length * 8);
InvShiftRows(ref state);
SubBytes(ref state, InvSBox);
for (int round = 9 + length * 2; round >= 1; round--)
{
AddRoundKey(ref state, AKey, round * 4);
InvMixColumns(ref state);
InvShiftRows(ref state);
SubBytes(ref state, InvSBox);
}
AddRoundKey(ref state, AKey, 0);
}
private static void MixColumns(ref byte[,] state)
{
byte[,] new_state = new byte[4, 4];
for (int c = 0; c < 4; c++)
{
new_state[0, c] = (byte)(PolynomsMult(2, state[0, c], 283) ^ PolynomsMult(3, state[1, c], 283) ^ state[2, c] ^ state[3, c]);
new_state[1, c] = (byte)(state[0, c] ^ PolynomsMult(2, state[1, c],283) ^ PolynomsMult(3, state[2, c], 283) ^ state[3, c]);
new_state[2, c] = (byte)(state[0, c] ^ state[1, c] ^ PolynomsMult(2, state[2, c],283) ^ PolynomsMult(3, state[3, c],283));
new_state[3, c] = (byte)(PolynomsMult(3, state[0, c],283) ^ state[1, c] ^ state[2, c] ^ PolynomsMult(2, state[3, c],283));
}
state = new_state;
return;
}
private static void InvMixColumns(ref byte[,] state)
{
byte[,] new_state = new byte[4, 4];
for (int c = 0; c < 4; c++)
{
new_state[0, c] = (byte)(AES.PolynomsMult(14, state[0, c], 283) ^ AES.PolynomsMult(11, state[1, c], 283) ^ AES.PolynomsMult(13, state[2, c], 283) ^ AES.PolynomsMult(9, state[3, c], 283));
new_state[1, c] = (byte)(AES.PolynomsMult(9, state[0, c], 283) ^ AES.PolynomsMult(14, state[1, c], 283) ^ AES.PolynomsMult(11, state[2, c], 283) ^ AES.PolynomsMult(13, state[3, c], 283));
new_state[2, c] = (byte)(AES.PolynomsMult(13, state[0, c], 283) ^ AES.PolynomsMult(9, state[1, c], 283) ^ AES.PolynomsMult(14, state[2, c], 283) ^ AES.PolynomsMult(11, state[3, c], 283));
new_state[3, c] = (byte)(AES.PolynomsMult(11, state[0, c], 283) ^ AES.PolynomsMult(13, state[1, c], 283) ^ AES.PolynomsMult(9, state[2, c], 283) ^ AES.PolynomsMult(14, state[3, c], 283));
}
state = new_state;
}
private static void ShiftRows(ref byte[,] state)
{
byte[,] temp = new byte[4,4];
for (int i = 0; i < 4; i++)
{
for (int q = 0; q < 4; q++)
temp[i, q] = state[i, (q + i) % 4];
}
state = temp;
}
private static void InvShiftRows(ref byte[,] state)
{
byte[,] temp = new byte[4, 4];
for (int i = 0; i < 4; i++)
{
for (int q = 0; q < 4; q++)
temp[i, q] = state[i, (q + 4 - i) % 4];
}
state = temp;
}
private static void SubBytes(ref byte[,] state, byte[] SBox)
{
for (int i = 0; i < 4; i++)
{
for (int q = 0; q < 4; q++)
{
state[i, q] = SBox[state[i,q]];
}
}
}
private static void AddRoundKey(ref byte[,] state, byte[,] AKey, int round)
{
for (int i = 0; i < 4; i++)
{
for (int q = 0; q < 4; q++)
{
state[i, q] ^= AKey[i,q+round];
}
}
}
#endregion
#region Encrypt or Decrypt text
public static void Encrypt(ref byte[] array, byte[] key)
{
byte[,] temp = new byte[4,4];
byte[] SBox = new byte[256];
Create_SBox(ref SBox);
/*Form1.Tabl = new string[16, 16];
int oi = 0;
for (int l = 0; l < 16; l++)
{
for (int q = 0; q < 16; q++)
{
Form1.Tabl[q, l] = Form1.ByteToHex(SBox[oi]);
oi++;
}
}*/
byte[,] AKey = KeyExpansion(key,SBox);
uint len = (uint)(array.Length / 16);
byte[] output = new byte[len*16];
byte j = 0;
for (int i = 0; i < len; i++)
{
for (int k = 0; k < 4; k++)
{
for (int q = 0; q < 4; q++)
{
temp[k, q] = array[16 * i + j];
j++;
}
}
j = 0;
Cipher(ref temp, AKey, SBox, Convert.ToByte((key.Length - 16) / 8));
for (int k = 0; k < 4; k++)
{
for (int q = 0; q < 4; q++)
{
output[16 * i + j] = temp[k,q];
j++;
}
}
j = 0;
}
array = output;
Array.Clear(AKey, 0, AKey.Length);
}
public static void Decrypt(ref byte[] array, byte[] key)
{
byte[,] temp = new byte[4,4];
byte[] InvSBox = new byte[256];
byte[] SBox = new byte[256];
Create_SBox(ref SBox);
Create_InvSBox(ref InvSBox);
/*Form1.Tabl = new string[16, 16];
int oi = 0;
for (int l = 0; l < 16; l++)
{
for (int q = 0; q < 16; q++)
{
Form1.Tabl[q, l] = Form1.ByteToHex(InvSBox[oi]);
oi++;
}
}*/
byte[,] AKey = KeyExpansion(key, SBox);
uint len = (uint)(array.Length / 16);
byte[] output = new byte[len * 16];
byte j = 0;
for (int i = 0; i < len; i++)
{
for (int k = 0; k < 4; k++)
{
for (int q = 0; q < 4; q++)
{
temp[k, q] = array[16 * i + j];
j++;
}
}
j = 0;
InvCipher(ref temp, AKey, InvSBox, Convert.ToByte((key.Length - 16) / 8));
for (int k = 0; k < 4; k++)
{
for (int q = 0; q < 4; q++)
{
output[16 * i + j] = temp[k, q];
j++;
}
}
j = 0;
}
array = output;
Array.Clear(AKey, 0, AKey.Length);
}
#endregion
#region Test
private static void test()
{
byte[,] state = new byte[4, 4];
state[0, 0] = 0x32;
state[0, 1] = 0x88;
state[0, 2] = 0x31;
state[0, 3] = 0xe0;
state[1, 0] = 0x43;
state[1, 1] = 0x5a;
state[1, 2] = 0x31;
state[1, 3] = 0x37;
state[2, 0] = 0xf6;
state[2, 1] = 0x30;
state[2, 2] = 0x98;
state[2, 3] = 0x07;
state[3, 0] = 0xa8;
state[3, 1] = 0x8d;
state[3, 2] = 0xa2;
state[3, 3] = 0x34;
byte[] key = new byte[16];
key[0] = 0x2b;
key[1] = 0x28;
key[2] = 0xab;
key[3] = 0x09;
key[4] = 0x7e;
key[5] = 0xae;
key[6] = 0xf7;
key[7] = 0xcf;
key[8] = 0x15;
key[9] = 0xd2;
key[10] = 0x15;
key[11] = 0x4f;
key[12] = 0x16;
key[13] = 0xa6;
key[14] = 0x88;
key[15] = 0x3c;
byte[] SBox = new byte[256];
byte[] InvSBox = new byte[256];
AES.Create_SBox(ref SBox);
AES.Create_InvSBox(ref InvSBox);
byte[,] AKey = AES.KeyExpansion(key, SBox);
AES.Cipher(ref state, AKey, SBox, 0);
AES.InvCipher(ref state, AKey, InvSBox, 0);
}
#endregion
}
}