Unit Mainprogram;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, Crypto, ExtCtrls,Advanced_Encryption_Standard;
Type
TForm1 =
Class(TForm)
Button1: TButton;
Memo1: TMemo;
LabeledEdit1: TLabeledEdit;
Button2: TButton;
Procedure Button1Click(Sender: TObject);
Procedure Button2Click(Sender: TObject);
Private
Public
{ Public declarations }
End;
Var
Form1: TForm1;
Aes: Taes;
Data: Tdata;
//datenverarbeitung und ausgabe
Implementation
{$R *.dfm}
Procedure TForm1.Button1Click(Sender: TObject);
Var
Text, Key:
String;
Begin
Text := Memo1.Text;
Key := Labelededit1.Text;
Text := Aes.Aes_text(Text, Key, Aes.Keysize128, 0);
Text := Data.Base64(Text, 0);
// Text := Data.Str_tohex(Text, Length(Text));
Memo1.Text := Text;
End;
Procedure TForm1.Button2Click(Sender: TObject);
Var
Text, Key:
String;
Begin
Text := Memo1.Text;
Key := Labelededit1.Text;
// Text := Data.Str_fromhex(Text);
Text := Data.Base64(Text, 1);
Text := Aes.Aes_text(Text, Key, Aes.Keysize128, 1);
Memo1.Text := Text;
End;
Initialization
Data := Tdata.Create;
Aes := Taes.Create;
Finalization
Aes.Free;
Data.Free;
End.
Unit Advanced_Encryption_Standard;
Interface
{$RANGECHECKS on}
{$OPTIMIZATION ON}
{$OVERFLOWCHECKS on}
Uses
Messages, SysUtils, Classes, StdCtrls;
Type
// 128 bit /16 byte /4*4 blocks for 128 bit key
Trow =
Array [1 .. 4]
Of Byte;
Tcolumn =
Array [1 .. 4]
Of Byte;
Tstate =
Array [1 .. 4]
Of Trow;
Tword =
Array [1 .. 4]
Of Byte;
Tinput =
Array [1 .. 16]
Of Byte;
//to fill a custom state
{ expanded key arrays
128 bit input block =>176 bytes=>11 16 byte blocks
192 bit input block=>208 bytes=> 8 24 byte bocks
256 bit input block=>240 bytes=> 7 32 byte blocks }
Tkey128 =
Array [1 .. 176]
Of Byte;
Tkey192 =
Array [1 .. 208]
Of Byte;
Tkey256 =
Array [1 .. 240]
Of Byte;
Tsubkeys128 =
Array [1 .. 11]
Of Tstate;
//counters i,j:=1<= 4
Taes =
Class
// Public
Var
Testroundkey: Tstate;
//for initalization keyschedule test
Testexpandedkey128: Tkey128;
Testcount: Integer;
Const
Keysize128 = 128;
Keysize192 = 192;
Keysize256 = 256;
Function Aes_text(
Var Text, Key:
String; Bitlen: Integer; Mode: Byte):
String;
Private
Var
Mixcolstate: Tstate;
Mixcolinvstate: Tstate;
Expandedkey128: Tkey128;
Expandedkey192: Tkey192;
Expandedkey256: Tkey256;
Keys:
Array Of String;
Const
Teststatearray: Tinput = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
Sbox:
Array [0 .. 255]
Of Byte =
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
($63, $7C, $77, $7B, $F2, $6B, $6F, $C5, $30, $01, $67, $2B, $FE, $D7, $AB, $76,
//0
$CA, $82, $C9, $7D, $FA, $59, $47, $F0, $AD, $D4, $A2, $AF, $9C, $A4, $72, $C0,
//1
$B7, $FD, $93, $26, $36, $3F, $F7, $
CC, $34, $A5, $E5, $F1, $71, $D8, $31, $15,
//2
$04, $C7, $23, $C3, $18, $96, $05, $9A, $07, $12, $80, $E2, $EB, $27, $B2, $75,
//3
$09, $83, $2C, $1A, $1B, $6E, $5A, $A0, $52, $3B, $D6, $B3, $29, $E3, $2F, $84,
//4
$53, $D1, $00, $ED, $20, $FC, $B1, $5B, $6A, $CB, $BE, $39, $4A, $4C, $58, $CF,
//5
$D0, $EF, $AA, $
FB, $43, $4D, $33, $85, $45, $F9, $02, $7F, $50, $3C, $9F, $A8,
//6
$51, $A3, $40, $8F, $92, $9D, $38, $F5, $BC, $B6, $DA, $21, $10, $FF, $F3, $D2,
//7
$CD, $0C, $13, $
EC, $5F, $97, $44, $17, $C4, $A7, $7E, $3D, $64, $5D, $19, $73,
//8
$60, $81, $4F, $
DC, $22, $2A, $90, $88, $46, $EE, $B8, $14, $DE, $5E, $0B, $
DB,
//9
$E0, $32, $3A, $0A, $49, $06, $24, $5C, $C2, $D3, $AC, $62, $91, $95, $E4, $79,
//A
$E7, $C8, $37, $6D, $8D, $D5, $4E, $A9, $6C, $56, $F4, $EA, $65, $7A, $AE, $08,
//B
$BA, $78, $25, $2E, $1C, $A6, $B4, $C6, $E8, $DD, $74, $1F, $4B, $BD, $8B, $8A,
//C
$70, $3E, $B5, $66, $48, $03, $F6, $0E, $61, $35, $57, $B9, $86, $C1, $1D, $9E,
//D
$E1, $F8, $98, $11, $69, $D9, $8E, $94, $9B, $1E, $87, $E9, $CE, $55, $28, $
DF,
//E
$8C, $A1, $89, $0D, $BF, $E6, $42, $68, $41, $99, $2D, $0F, $B0, $54, $BB, $16);
//F
Invsbox:
Array [0 .. 255]
Of Byte =
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
($52, $09, $6A, $D5, $30, $36, $A5, $38, $BF, $40, $A3, $9E, $81, $F3, $D7, $
FB,
//0
$7C, $E3, $39, $82, $9B, $2F, $FF, $87, $34, $8E, $43, $44, $C4, $DE, $E9, $CB,
//1
$54, $7B, $94, $32, $A6, $C2, $23, $3D, $EE, $4C, $95, $0B, $42, $FA, $C3, $4E,
//2
$08, $2E, $A1, $66, $28, $D9, $24, $B2, $76, $5B, $A2, $49, $6D, $8B, $D1, $25,
//3
$72, $F8, $F6, $64, $86, $68, $98, $16, $D4, $A4, $5C, $
CC, $5D, $65, $B6, $92,
//4
$6C, $70, $48, $50, $FD, $ED, $B9, $DA, $5E, $15, $46, $57, $A7, $8D, $9D, $84,
//5
$90, $D8, $AB, $00, $8C, $BC, $D3, $0A, $F7, $E4, $58, $05, $B8, $B3, $45, $06,
//6
$D0, $2C, $1E, $8F, $CA, $3F, $0F, $02, $C1, $AF, $BD, $03, $01, $13, $8A, $6B,
//7
$3A, $91, $11, $41, $4F, $67, $
DC, $EA, $97, $F2, $CF, $CE, $F0, $B4, $E6, $73,
//8
$96, $AC, $74, $22, $E7, $AD, $35, $85, $E2, $F9, $37, $E8, $1C, $75, $
DF, $6E,
//9
$47, $F1, $1A, $71, $1D, $29, $C5, $89, $6F, $B7, $62, $0E, $AA, $18, $BE, $1B,
//A
$FC, $56, $3E, $4B, $C6, $D2, $79, $20, $9A, $
DB, $C0, $FE, $78, $CD, $5A, $F4,
//B
$1F, $DD, $A8, $33, $88, $07, $C7, $31, $B1, $12, $10, $59, $27, $80, $
EC, $5F,
//C
$60, $51, $7F, $A9, $19, $B5, $4A, $0D, $2D, $E5, $7A, $9F, $93, $C9, $9C, $EF,
//D
$A0, $E0, $3B, $4D, $AE, $2A, $F5, $B0, $C8, $EB, $BB, $3C, $83, $53, $99, $61,
//E
$17, $2B, $04, $7E, $BA, $77, $D6, $26, $E1, $69, $14, $63, $55, $21, $0C, $7D);
//F
Procedure Aes128_Keyschedule_test(
Var Keys:
Array Of String);
Procedure Keyschedule_core(
Var Word: Tword; Iteration: Integer; Mode: Byte);
Function Multcolumn(Column: Tcolumn; Mode: Byte): Tcolumn;
Function Galois_mult(A, B: Byte): Byte;
//http://en.wikipedia.org/wiki/Rijndael_mix_columns
Procedure Shiftrows(
Var State: Tstate; Mode: Byte);
Procedure Rotate(
Var Value: Tword; Mode: Byte);
// rotate(1d 2c 3a 4f) = 2c 3a 4f 1d
Procedure AddRoundKey(
Var State: Tstate; Roundkey: Tstate);
Function Getsboxvalue(
Index: Byte): Byte;
Function Getinvsboxvalue(
Index: Byte): Byte;
Function Rcon(
Index: Byte): Integer;
Function Expandkey(Key: Tinput;
Var Expandedkey: Tkey128): Byte;
Overload;
//result=number of rounds
Function Generatesubkeys(Expandedkey: Tkey128): Tsubkeys128;
Function Expandkey(Key: Tinput;
Var Expandedkey: Tkey192): Byte;
Overload;
//result=number of rounds
Function Expandkey(Key: Tinput;
Var Expandedkey: Tkey256): Byte;
Overload;
//result=number of rounds
Procedure Mixcolumns(
Var State: Tstate; Mode: Byte);
Procedure Subbytes(
Var State: Tstate; Mode: Byte);
Overload;
Procedure Subbytes(
Var Word: Tword)
Overload;
Procedure Showstate(State: Tstate; Memo: Tmemo);
Function Texttostate(Substr:
String): Tstate;
Function Texttokey(Key:
String): Tinput;
Function Keytostate(Data: Tinput): Tstate;
Function Statetotext(State: Tstate):
String;
Procedure Aes(Roundcount: Byte;
Var State: Tstate; Keys: Tsubkeys128; Mode: Byte);
End;
Implementation
{ src: http://en.wikipedia.org/wiki/Rijndael_mix_columns: A c# example
Multiplication in Rijndael's galois field is a little more complicated. The procedure is as follows:
* Take two eight-bit numbers, a and b, and an eight-bit product p
* Set the product to zero.
* Make a copy of a and b, which we will simply call a and b in the rest of this algorithm
* Run the following loop eight times:
1. If the low bit of b is set, exclusive or the product p by the value of a
2. Keep track of whether the high (eighth from left) bit of a is set to one
3. Rotate a one bit to the left, discarding the high bit, and making the low bit have a value of zero
4. If a's hi bit had a value of one prior to this rotation, exclusive or a with the hexadecimal number 0x1b
5. Rotate b one bit to the right, discarding the low bit, and making the high (eighth from left) bit have a value of zero.
6. The product p now has the product of a and b
}
//------------------------------------------------------------------------------
{
The Key Schedule is responsible for expanding a short key into a larger key,
whose parts are used during the different iterations. Each key size is expanded
to a different size:
An 128 bit key is expanded to an 176 byte key.
An 192 bit key is expanded to an 208 byte key.
An 256 bit key is expanded to an 240 byte key.
There is a relation between the cipher key size,
the number of rounds and the ExpandedKey size.
For an 128-bit key, there is one initial AddRoundKey operation
plus there are 10 rounds and each rounds need a new 16 byte key,
therefor we require 10+1 RoundKeys of 16 byte, which equals 176 byte.
The same logic can be applied to the two other cipher key sizes.
The general formula is that: ExpandedKeySize = (nbrRounds+1) * BlockSize
}
Procedure Taes.Aes128_Keyschedule_test(
Var Keys:
Array Of String);
Var
I, J, K: Integer;
Aes128:
Array Of Tkey128;
Begin
Setlength(Aes128, Length(Keys));
J := 0;
While J < 3
Do
Begin
Keys[J] := '
';
I := 1;
While I <= 16
Do
Begin
Case J
Of
1:
Keys[J] := Keys[J] + Chr(0);
{
should be:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
62 63 63 63 62 63 63 63 62 63 63 63 62 63 63 63
9B 98 98 C9 F9 FB FB AA 9B 98 98 C9 F9 FB FB AA
90 97 34 50 69 6C CF FA F2 F4 57 33 0B 0F AC 99
EE 06 DA 7B 87 6A 15 81 75 9E 42 B2 7E 91 EE 2B
7F 2E 2B 88 F8 44 3E 09 8D DA 7C BB F3 4B 92 90
EC 61 4B 85 14 25 75 8C 99 FF 09 37 6A B4 9B A7
21 75 17 87 35 50 62 0B AC AF 6B 3C C6 1B F0 9B
0E F9 03 33 3B A9 61 38 97 06 0A 04 51 1D FA 9F
B1 D4 D8 E2 8A 7D B9 DA 1D 7B B3 DE 4C 66 49 41
B4 EF 5B CB 3E 92 E2 11 23 E9 51 CF 6F 8F 18 8E
}
2:
Keys[J] := Keys[J] + Chr(Strtoint('
$FF'));
{
should be:
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
E8 E9 E9 E9 17 16 16 16 E8 E9 E9 E9 17 16 16 16
AD AE AE 19 BA B8 B8 0F 52 51 51 E6 45 47 47 F0
09 0E 22 77 B3 B6 9A 78 E1 E7 CB 9E A4 A0 8C 6E
E1 6A BD 3E 52 DC 27 46 B3 3B EC D8 17 9B 60 B6
E5 BA F3 CE B7 66 D4 88 04 5D 38 50 13 C6 58 E6
71 D0 7D B3 C6 B6 A9 3B C2 EB 91 6B D1 2D C9 8D
E9 0D 20 8D 2F BB 89 B6 ED 50 18 DD 3C 7D D1 50
96 33 73 66 B9 88 FA D0 54 D8 E2 0D 68 A5 33 5D
8B F0 3F 23 32 78 C5 F3 66 A0 27 FE 0E 05 14 A3
D6 0A 35 88 E4 72 F0 7B 82 D2 D7 85 8C D7 C3 26
}
3:
Keys[J] := Keys[J] + Chr(I - 1);
{ should be:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
D6 AA 74 FD D2 AF 72 FA DA A6 78 F1 D6 AB 76 FE
B6 92 CF 0B 64 3D BD F1 BE 9B C5 00 68 30 B3 FE
B6 FF 74 4E D2 C2 C9 BF 6C 59 0C BF 04 69 BF 41
47 F7 F7 BC 95 35 3E 03 F9 6C 32 BC FD 05 8D FD
3C AA A3 E8 A9 9F 9D EB 50 F3 AF 57 AD F6 22 AA
5E 39 0F 7D F7 A6 92 96 A7 55 3D C1 0A A3 1F 6B
14 F9 70 1A E3 5F E2 8C 44 0A DF 4D 4E A9 C0 26
47 43 87 35 A4 1C 65 B9 E0 16 BA F4 AE BF 7A D2
54 99 32 D1 F0 85 57 68 10 93 ED 9C BE 2C 97 4E
13 11 1D 7F E3 94 4A 17 F3 07 A7 8B 4D 2B 30 C5
}
End;
Inc(I);
End;
Expandkey(Texttokey(Keys[J]), Aes128[J]);
Keys[J] := '
';
K := 1;
While K <= Length(Aes128[J])
Do
Begin
Keys[J] := Keys[J] + Inttohex(Aes128[J][K], 2) + Chr(32);
If K
Mod 16 = 0
Then
Keys[J] := Keys[J] + #13#10;
Inc(K);
End;
Inc(J);
End;
End;
Procedure Taes.Keyschedule_core(
Var Word: Tword; Iteration: Integer; Mode: Byte);
Begin
Rotate(Word, Mode);
Subbytes(Word);
Word[1] := Word[1]
Xor Byte(Rcon(Iteration));
End;
Function Taes.Galois_mult(A, B: Byte): Byte;
//http://en.wikipedia.org/wiki/Rijndael_mix_columns
Var
P, Counter, Hi_bit_set: Byte;
Aa, Bb: Byte;
Begin
Aa := A;
Bb := B;
P := 0;
Counter := 0;
While Counter < 8
Do
Begin
If (Bb
And 1) <> 0
Then
P := P
Xor Aa;
Hi_bit_set := Byte(Aa
And $80);
//Mod 256;
Aa := Byte(Aa
Shl 1);
If Hi_bit_set <> 0
Then
Aa := Byte(Aa
Xor $1b);
//x^8+x^4+x^3+x^2+x+1
Bb := Bb
Shr 1;
Inc(Counter);
End;
Result := P;
End;
Function Taes.Multcolumn(Column: Tcolumn; Mode: Byte): Tcolumn;
//multiplies a column with the MDS matrix
{
mds=
2 3 1 1
1 2 3 1
1 1 2 3
3 1 1 2
mdsinv=
14 11 13 9
9 14 11 13
13 9 14 11
11 13 9 14
where + = xor, x = galois-multiplication }
Begin
Case Mode
Of
0:
Begin
Result[1] := (((Galois_mult(2, Column[1])
Xor Galois_mult(3, Column[2]))
Xor Galois_mult
(1, Column[3]))
Xor Galois_mult(1, Column[4]));
Result[2] := (((Galois_mult(1, Column[1])
Xor Galois_mult(2, Column[2]))
Xor Galois_mult
(3, Column[3]))
Xor Galois_mult(1, Column[4]));
Result[3] := (((Galois_mult(1, Column[1])
Xor Galois_mult(1, Column[2]))
Xor Galois_mult
(2, Column[3]))
Xor Galois_mult(3, Column[4]));
Result[4] := (((Galois_mult(3, Column[1])
Xor Galois_mult(1, Column[2]))
Xor Galois_mult
(1, Column[3]))
Xor Galois_mult(2, Column[4]));
End;
1:
Begin
Result[1] := (((Galois_mult(14, Column[1])
Xor Galois_mult(11, Column[2]))
Xor Galois_mult
(13, Column[3]))
Xor Galois_mult(9, Column[4]));
Result[2] := (((Galois_mult(9, Column[1])
Xor Galois_mult(14, Column[2]))
Xor Galois_mult
(11, Column[3]))
Xor Galois_mult(13, Column[4]));
Result[3] := (((Galois_mult(13, Column[1])
Xor Galois_mult(9, Column[2]))
Xor Galois_mult
(14, Column[3]))
Xor Galois_mult(11, Column[4]));
Result[4] := (((Galois_mult(11, Column[1])
Xor Galois_mult(13, Column[2]))
Xor Galois_mult
(9, Column[3]))
Xor Galois_mult(14, Column[4]));
End;
End;
End;
Procedure Taes.Mixcolumns(
Var State: Tstate; Mode: Byte);
Var
Column: Tcolumn;
I, J: Integer;
Begin
//identify columns
J := 1;
While J <= 4
Do
Begin
I := 1;
While I <= 4
Do
Begin
Column[I] := State[I][J];
Inc(I);
End;
Column := Multcolumn(Column, Mode);
I := 1;
While I <= 4
Do
Begin
State[I][J] := Column[I];
Inc(I);
End;
Inc(J);
End;
End;
Procedure Taes.Subbytes(
Var State: Tstate; Mode: Byte);
//ok
Var
X: Byte;
I, J: Integer;
Begin
I := 1;
While I <= 4
Do
Begin
J := 1;
While J <= 4
Do
Begin
X := State[I][J];
Case Mode
Of
0:
X := Sbox[X];
1:
X := Invsbox[X];
End;
State[I][J] := X;
Inc(J);
End;
Inc(I);
End;
End;
Procedure Taes.Subbytes(
Var Word: Tword);
Var
I: Integer;
Begin
I := 1;
While I <= 4
Do
Begin
Word[I] := GetSBoxValue(Word[I]);
Inc(I);
End;
End;
Function Taes.Rcon(
Index: Byte): Integer;
Var
C, B: Integer;
Begin
If Index = 0
Then
Result := $8d
Else
Begin
C := 1;
While Index <> 1
Do
Begin
B := C
And $80;
C := C
Shl 1;
If B = $80
Then
C := C
Xor $1b;
Dec(
Index);
End;
Result := C;
End;
End;
(* orig c code:
-----------------
{
unsigned char c=1;
if(in == 0)
return 0;
while(in != 1) {
unsigned char b;
b = c & 0x80;
c <<= 1;
if(b == 0x80) {
c ^= 0x1b;
}
in--;
}
return c;
}
-----------------
*)
Function Taes.Expandkey(Key: Tinput;
Var Expandedkey: Tkey128): Byte;
//correct!
//expands given key (128,192,256 bit, determined by bitlen variable) to (176,208,240 bytes)
//blocksize=16=>keysize 128 bit
//result:= the number of rounds (10,12,14) determined by new keylength
//SRC= http://www.samiam.org/key-schedule.html
//http://cboard.cprogramming.com/c-programming/87805-%5Btutorial%5D-implementing-advanced-encryption-standard.html
Var
I, Rconiterator, A, C: Integer;
Temp: Tword;
Begin
I := 1;
While I <= Length(Key)
Do
Begin
Expandedkey[I] := Key[I];
Inc(I);
End;
Rconiterator := 1;
C := Length(Key) + 1;
//17
While C <= 176
Do
Begin
{ Copy the temporary variable over from the last 4-byte- block }
A := 1;
While A <= 4
Do
Begin
Temp[A] := Expandedkey[A + C - 5];
Inc(A);
End;
If ((C - 1)
Mod 16 = 0)
Then
Begin
Keyschedule_core(Temp, Rconiterator, 0);
Inc(Rconiterator);
End;
A := 1;
While A <= 4
Do
Begin
Expandedkey[C] := Expandedkey[C - 16]
Xor Temp[A];
Inc(C);
Inc(A);
End;
End;
Result := 11;
//number of rounds for 128 bit keys
End;
Function Taes.Generatesubkeys(Expandedkey: Tkey128): Tsubkeys128;
Var
I, J, K: Byte;
X: Byte;
Subkeystate: Tstate;
Subkey: Tinput;
Begin
I := 1;
X := 1;
While I < Length(Expandedkey)
Do
Begin
J := I;
K := 1;
While K <= 16
Do
Begin
Subkey[K] := Expandedkey[J];
Inc(K);
Inc(J);
End;
Subkeystate := Keytostate(Subkey);
Result[X] := Subkeystate;
Inc(X);
I := J;
End;
End;
Function Taes.Expandkey(Key: Tinput;
Var Expandedkey: Tkey192): Byte;
//expands given key (128,192,256 bit, determined by bitlen variable) to (176,208,240 bytes)
//blocksize=16=>keysize 128 bit
//result:=new keylength(determines the number of rounds (10,12,14)
//SRC= http://www.samiam.org/key-schedule.html
//http://cboard.cprogramming.com/c-programming/87805-%5Btutorial%5D-implementing-advanced-encryption-standard.html
Var
I: Integer;
Currentsize, Size: Integer;
Rconiteration: Integer;
Temp: Tword;
Begin
Rconiteration := 1;
Size := Length(Key);
I := 1;
While I <= 4
Do
Begin
Temp[I] := 0;
Inc(I);
End;
Currentsize := 0;
I := 1;
While I <= Size
Do
Begin
Expandedkey[I] := Key[I];
Inc(I);
End;
Currentsize := Currentsize + Size;
// assign the previous 4 bytes to the temporary value t
While Currentsize < Length(Expandedkey)
Do
Begin
I := 1;
While I <= 4
Do
Begin
Temp[I] := Expandedkey[(Currentsize - 4) + I];
Inc(I);
End;
//every 16,24,32 bytes (respective length of tinput) we apply the core schedule to t and increment rconIteration afterwards
If Currentsize
Mod Size = 0
Then
Begin
Keyschedule_core(Temp, Rconiteration + 1, 0);
Inc(Rconiteration);
End;
{
We XOR t with the four-byte block 16,24,32 bytes before the new expanded key.
* This becomes the next four bytes in the expanded key.
}
I := 1;
While I <= 4
Do
Begin
Expandedkey[Currentsize] := Expandedkey[Currentsize - Size]
Xor Temp[I];
Inc(Currentsize);
Inc(I);
End;
End;
Result := 12;
//number of rounds for 192 bit keys
End;
Function Taes.Expandkey(Key: Tinput;
Var Expandedkey: Tkey256): Byte;
//expands given key (128,192,256 bit, determined by bitlen variable) to (176,208,240 bytes)
//blocksize=16=>keysize 128 bit
//result:=new keylength(determines the number of rounds (10,12,14)
//SRC= http://www.samiam.org/key-schedule.html
//http://cboard.cprogramming.com/c-programming/87805-%5Btutorial%5D-implementing-advanced-encryption-standard.html
Var
I: Integer;
Currentsize, Size: Integer;
Rconiteration: Integer;
Temp: Tword;
Begin
Rconiteration := 1;
Size := Length(Key);
I := 1;
While I <= 4
Do
Begin
Temp[I] := 0;
Inc(I);
End;
Currentsize := 0;
I := 1;
While I <= Size
Do
Begin
Expandedkey[I] := Key[I];
Inc(I);
End;
Currentsize := Currentsize + Size;
// assign the previous 4 bytes to the temporary value t
While Currentsize < Length(Expandedkey)
Do
Begin
I := 1;
While I <= 4
Do
Begin
Temp[I] := Expandedkey[(Currentsize - 4) + I];
Inc(I);
End;
//every 16,24,32 bytes (respective length of tinput) we apply the core schedule to t and increment rconIteration afterwards
If Currentsize
Mod Size = 0
Then
Begin
Keyschedule_core(Temp, Rconiteration + 1, 0);
Inc(Rconiteration);
End;
//applies only to 256 bit keys: For 256-bit keys, we add an extra sbox to the calculation
If (Size = 32)
And (Currentsize
Mod Size = 16)
Then
Begin
I := 1;
While I <= 4
Do
Begin
Temp[I] := Getsboxvalue(Temp[I]);
Inc(I);
End;
End;
{
We XOR t with the four-byte block 16,24,32 bytes before the new expanded key.
* This becomes the next four bytes in the expanded key.
}
I := 1;
While I <= 4
Do
Begin
Expandedkey[Currentsize] := Expandedkey[Currentsize - Size]
Xor Temp[I];
Inc(Currentsize);
Inc(I);
End;
End;
Result := 14;
//number of rounds for 256 bit keys
End;
Function Taes.Texttostate(Substr:
String): Tstate;
//max length 16!!
Var
I, J: Integer;
Row: Trow;
Begin
If Length(Substr) > 16
Then
Begin
Raise Exception.Create('
No valid substring length');
Exit;
End;
I := 1;
While I <= 4
Do
Begin
J := 1;
While J <= 4
Do
Begin
Row[J] := Ord(Substr[J + 4 * (I - 1)]);
Inc(J);
End;
Result[I] := Row;
Inc(I);
End;
End;
Function Taes.Keytostate(Data: Tinput): Tstate;
Var
I, J: Integer;
Row: Trow;
Begin
I := 1;
While I <= 4
Do
Begin
J := 1;
While J <= 4
Do
Begin
Row[J] := Ord(Data[J + 4 * (I - 1)]);
Inc(J);
End;
Result[I] := Row;
Inc(I);
End;
End;
Function Taes.Statetotext(State: Tstate):
String;
Var
I, J: Int64;
Begin
Result := '
';
I := 1;
While I <= 4
Do
Begin
J := 1;
While J <= 4
Do
Begin
Result := Result + Chr(State[I][J]);
Inc(J);
End;
Inc(I);
End;
End;
Function Taes.Texttokey(Key:
String): Tinput;
Var
I: Byte;
Begin
If Length(Key) > 16
Then
Raise Exception.Create('
Keylength not accepted. Must be <=16')
Else
Begin
I := 1;
While I <= Length(Key)
Do
Begin
Result[I] := Ord(Key[I]);
Inc(I);
End;
While I < 16
Do
Begin
Result[I] := 0;
Inc(I);
End;
End;
End;
Procedure Taes.Showstate(State: Tstate; Memo: Tmemo);
Var
I, J: Integer;
Row: Trow;
R:
String;
Begin
I := 1;
While I <= 4
Do
Begin
J := 1;
R := '
';
While J <= 4
Do
Begin
Row[J] := State[I][J];
R := R + Inttostr(Row[J]) + Chr(32);
Inc(J);
End;
Memo.Lines.Add(R);
Inc(I);
End;
End;
Procedure Taes.Shiftrows(
Var State: Tstate; Mode: Byte);
//ok
Function Rowshift(Row: Trow; Count, Mode: Byte): Trow;
Var
I, K: Integer;
Begin
I := 1;
While I <= 4
Do
Begin
If Mode = 0
Then
Begin
K := (I + Count);
If K > 4
Then
K := K - 4;
End
Else If Mode = 1
Then
Begin
K := (I - Count);
If K < 1
Then
K := K + 4;
End;
Result[I] := Row[K];
Inc(I);
End;
End;
Var
I: Integer;
Begin
If (Mode = 0)
Or (Mode = 1)
Then
Begin
I := 1;
While I <= 4
Do
Begin
State[I] := Rowshift(State[I], I - 1, Mode);
Inc(I);
End;
End
Else
Exit;
End;
// rotate(1d 2c 3a 4f) = 2c 3a 4f 1d
//tword is 4byte long, Rotation 8 bit (=1byte) to the left=shifting one entry to the left
Procedure Taes.Rotate(
Var Value: Tword; Mode: Byte);
Var
I, J: Byte;
Result: Tword;
Begin
Case Mode
Of
0:
Begin
I := 1;
While I <= 4
Do
Begin
J := I + 1;
If J > 4
Then
J := J - 4;
Result[I] := Value[J];
Inc(I);
End;
End;
1:
Begin
I := 1;
While I <= 4
Do
Begin
J := I - 1;
If J <= 0
Then
J := J + 4;
Result[I] := Value[J];
Inc(I);
End;
End;
End;
Value := Result;
End;
Procedure Taes.AddRoundKey(
Var State: Tstate; Roundkey: Tstate);
Var
I, J: Integer;
Begin
I := 1;
While I <= 4
Do
Begin
J := 1;
While J <= 4
Do //one row
Begin
State[I][J] := State[I][J]
Xor Roundkey[I][J];
Inc(J);
End;
Inc(I);
End;
End;
Function Taes.Getsboxvalue(
Index: Byte): Byte;
Begin
Result := Sbox[
Index];
End;
Function Taes.Getinvsboxvalue(
Index: Byte): Byte;
Begin
Result := Invsbox[
Index];
End;
Procedure Taes.Aes(Roundcount: Byte;
Var State: Tstate; Keys: Tsubkeys128; Mode: Byte);
Var
I: Integer;
Begin
If Mode = 0
Then
Begin
I := 1;
Addroundkey(State, Keys[I]);
Inc(I);
While I <= Roundcount - 1
Do
Begin
Subbytes(State, Mode);
Shiftrows(State, Mode);
Mixcolumns(State, Mode);
Addroundkey(State, Keys[I]);
Inc(I);
End;
// final round :
Subbytes(State, Mode);
Shiftrows(State, Mode);
Addroundkey(State, Keys[I]);
End
Else
Begin
I := Roundcount;
//decryption= go backwards from last step on
Addroundkey(State, Keys[I]);
Shiftrows(State, Mode);
Subbytes(State, Mode);
I := I - 1;
While I >= 2
Do
Begin
Addroundkey(State, Keys[I]);
Mixcolumns(State, Mode);
Shiftrows(State, Mode);
Subbytes(State, Mode);
Dec(I);
End;
Addroundkey(State, Keys[I]);
End;
End;
Function Taes.Aes_text(
Var Text, Key:
String; Bitlen: Integer; Mode: Byte):
String;
Var
Substr:
String;
I, J, Textlen: Int64;
State: Tstate;
Keystate: Tinput;
Roundcount: Integer;
Subkeys: Tsubkeys128;
Begin
Textlen := Length(Text);
//padding
While Textlen
Mod 16 <> 0
Do
Begin
Text := Text + Chr(0);
Inc(Textlen);
End;
Keystate := Texttokey(Key);
Case Bitlen
Of
128:
Roundcount := Expandkey(Keystate, Expandedkey128);
192:
Roundcount := Expandkey(Keystate, Expandedkey192);
256:
Roundcount := Expandkey(Keystate, Expandedkey256);
Else
Begin
Result := Text;
Raise Exception.Create('
Keysize not accepted.');
End;
End;
Subkeys := Generatesubkeys(Expandedkey128);
If Roundcount <> -1
Then
Begin
I := 1;
While I <= Textlen
Do
Begin
J := I;
Substr := '
';
While J < I + 16
Do
Begin
Substr := Substr + Text[J];
Inc(J);
End;
State := Texttostate(Substr);
Aes(Roundcount, State, Subkeys, Mode);
Substr := Statetotext(State);
Result := Result + Substr;
I := J;
End;
End
Else
Result := Text;
//an error occurred
End;
End.