1-- This program is free software; you can redistribute it and/or
2-- modify it under the terms of the GNU General Public License as
3-- published by the Free Software Foundation; either version 2 of the
4-- License, or (at your option) any later version.
5
6-- This program is distributed in the hope that it will be useful,
7-- but WITHOUT ANY WARRANTY; without even the implied warranty of
8-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9-- General Public License for more details.
10
11-- You should have received a copy of the GNU General Public License
12-- along with this program; if not, write to the Free Software
13-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
14-- 02111-1307, USA.
15
16-- As a special exception, if other files instantiate generics from
17-- this unit, or you link this unit with other files to produce an
18-- executable, this unit does not by itself cause the resulting
19-- executable to be covered by the GNU General Public License. This
20-- exception does not however invalidate any other reasons why the
21-- executable file might be covered by the GNU Public License.
22
23with Crypto.Symmetric.Algorithm.Aes.Tables;
24use  Crypto.Symmetric.Algorithm.Aes.Tables;
25
26package body Crypto.Symmetric.Algorithm.AES is
27
28
29   ---------------------------------------------------------------------------
30   --------------------------BUILD_ENCRYPT_KEY--------------------------------
31   ---------------------------------------------------------------------------
32
33   procedure Build_Encrypt_Key(Key : in Bytes;
34                               Encrypt_Key : in out Words;
35                               Nk : in Positive) is
36      Temp : Word;
37
38   begin
39      -- copy user material bytes into temporary ints
40      for I in 0..Nk-1 loop
41         Encrypt_Key(I) := To_Word(Key(Nb*i),   Key(Nb*i+1),
42                                              Key(Nb*i+2), Key(Nb*i+3));
43      end loop;
44      for I in Nk..Encrypt_Key'Length-1 loop
45         Temp  := Encrypt_Key(I-1);
46
47         if (I mod Nk) = 0 then
48            Temp := To_Word(S(Byte1(Temp)), S(Byte2(Temp)),
49                                  S(Byte3(Temp)), S(Byte0(Temp)))
50              xor Rcon(I / Nk );
51
52         elsif (Nk > 6) and ((I mod Nk) = Nb) then
53            Temp:=To_Word(S(Byte0(Temp)), S(Byte1(Temp)),
54                                S(Byte2(Temp)), S(Byte3(Temp)));
55         end if;
56
57         Encrypt_Key(I) := Encrypt_Key(I-Nk) xor Temp;
58
59      end loop;
60   end Build_Encrypt_Key;
61
62   -------------------------------------------------------------------------
63   -------------------------BUILD_DECRYPT_KEY-------------------------------
64   -------------------------------------------------------------------------
65
66   procedure Build_Decrypt_Key(Encrypt_Key : in Words;
67                               Decrypt_Key : out Words) is
68
69      Rounds : constant Positive := Encrypt_Key'Length/Nb-1;
70      A0, A1, A2, A3 : Word; -- Working variables
71      Index : Natural:=Nb; -- current Roundkey index
72   begin
73
74      Decrypt_Key := Encrypt_Key;
75
76      for R in 1..Rounds-1 loop -- R*Nb
77         A0 := Decrypt_Key(Index); -- Index = R*Nb
78         Index:=Index+1;
79         A1 := Decrypt_Key(Index); -- Index = R*Nb+1
80         Index:=Index+1;
81         A2 := Decrypt_Key(Index); -- Index = R*Nb+2
82         Index:=Index+1;
83         A3 := Decrypt_Key(Index); -- Index := R*Nb+3
84
85         Index:=Index-3; -- Index := R*Nb;
86
87         Decrypt_Key(Index) := U1(Byte0(A0)) xor U2(Byte1(A0)) xor
88           U3(Byte2(A0)) xor U4(Byte3(A0));
89         Index:= Index+1; -- Index := R*Nb+1;
90         Decrypt_Key(Index) := U1(Byte0(A1)) xor U2(Byte1(A1)) xor
91           U3(Byte2(A1)) xor U4(Byte3(A1));
92         Index:= Index+1; -- Index := R*Nb+2;
93         Decrypt_Key(Index) := U1(Byte0(A2)) xor U2(Byte1(A2)) xor
94           U3(Byte2(A2)) xor U4(Byte3(A2));
95         Index:= Index+1; -- Index := R*Nb+3;
96         Decrypt_Key(Index) := U1(Byte0(A3)) xor U2(Byte1(A3)) xor
97           U3(Byte2(A3)) xor U4(Byte3(A3));
98         Index:= Index+1; -- Index := (R+1)*Nb;
99      end loop;
100
101   end Build_Decrypt_KEY;
102
103   -------------------------------------------------------------------------
104   ---------------------------PREPARE_KEY-----------------------------------
105   -------------------------------------------------------------------------
106
107   procedure Prepare_Key128(Key       : in B_Block128;
108                             Cipherkey : out Cipherkey_AES128) is
109   begin
110      Build_Encrypt_Key(Bytes(Key), Words(Cipherkey.Encrypt_Key), Nk=> Nk128);
111      Build_Decrypt_Key(Words(Cipherkey.Encrypt_Key),
112                        Words(Cipherkey.Decrypt_Key));
113   end Prepare_Key128;
114
115   ---------------------------------------------------------------------------
116
117   procedure Prepare_Key192(Key       : in B_Block192;
118                             Cipherkey : out Cipherkey_AES192) is
119   begin
120      Build_Encrypt_Key(Bytes(Key), Words(Cipherkey.Encrypt_Key), Nk=> Nk192);
121      Build_Decrypt_Key(Words(Cipherkey.Encrypt_Key),
122                        Words(Cipherkey.Decrypt_Key));
123   end Prepare_Key192;
124
125   ---------------------------------------------------------------------------
126
127   procedure Prepare_Key256(Key : in B_Block256;
128                            Cipherkey : out Cipherkey_AES256) is
129   begin
130      Build_Encrypt_Key(Bytes(Key), Words(Cipherkey.Encrypt_Key),
131                              Nk=> Nk256);
132      Build_Decrypt_Key(Words(Cipherkey.Encrypt_Key),
133                        Words(Cipherkey.Decrypt_Key));
134   end Prepare_Key256;
135
136   -------------------------------------------------------------------------
137   ------------------------------ENCRYPT------------------------------------
138   -------------------------------------------------------------------------
139
140   function Encrypt(Encrypt_Key : in Words; Plaintext : in B_Block128)
141                   return  B_Block128 is
142      X0, X1, X2, X3  : Word;
143      A0, A1, A2, A3  : Word;
144      Index : Natural := Nb; -- current Encrypt_Key index
145      Ciphertext      : B_Block128;
146      Rounds          : constant  Positive:= Encrypt_Key'Length/Nb-1;
147   begin
148
149      X0 := To_Word(Plaintext(0), Plaintext(1), Plaintext(2),
150                          Plaintext(3)) xor Encrypt_Key(0);
151      X1 := To_Word(Plaintext(4), Plaintext(5), Plaintext(6),
152                          Plaintext(7)) xor Encrypt_Key(1);
153      X2 := To_Word(Plaintext(8), Plaintext(9), Plaintext(10),
154                          Plaintext(11)) xor Encrypt_Key(2);
155      X3 := To_Word(Plaintext(12), Plaintext(13), Plaintext(14),
156                          Plaintext(15)) xor Encrypt_Key(3);
157
158
159
160      -- AES with table lookup ("The Rijndael Block Cipher",
161      -- AES Proposal, Document version 2, Date:03/09/99,  page 18)
162      for R in 1..Rounds-1 loop
163         A0 := (T1(Byte0(X0))  xor T2(Byte1(X1)) xor T3(Byte2(X2)) xor
164                T4(Byte3(X3))) xor Encrypt_Key(Index);
165         Index := Index+1;
166         A1 := (T1(Byte0(X1))  xor T2(Byte1(X2)) xor T3(Byte2(X3)) xor
167                T4(Byte3(X0))) xor Encrypt_Key(Index);
168         Index := Index+1;
169         A2 := (T1(Byte0(X2))  xor T2(Byte1(X3)) xor T3(Byte2(X0)) xor
170                T4(Byte3(X1))) xor Encrypt_Key(Index);
171         Index := Index+1;
172         A3 := (T1(Byte0(X3))  xor T2(Byte1(X0)) xor T3(Byte2(X1)) xor
173                T4(Byte3(X2))) xor Encrypt_Key(Index);
174
175         Index := Index+1; -- Index := (R+1)*Nb;
176
177         X0 := A0;
178         X1 := A1;
179         X2 := A2;
180         X3 := A3;
181
182      end loop;
183
184      -- Index = Rounds*Nb
185
186        -- last round is special
187      Ciphertext(0)  := S(Byte0(X0)) xor Byte0(Encrypt_Key(Index));
188      Ciphertext(1)  := S(Byte1(X1)) xor Byte1(Encrypt_Key(Index));
189      Ciphertext(2)  := S(Byte2(X2)) xor Byte2(Encrypt_Key(Index));
190      Ciphertext(3)  := S(Byte3(X3)) xor Byte3(Encrypt_Key(Index));
191
192      Index := Index+1;
193
194      Ciphertext(4)  := S(Byte0(X1)) xor Byte0(Encrypt_Key(Index));
195      Ciphertext(5)  := S(Byte1(X2)) xor Byte1(Encrypt_Key(Index));
196      Ciphertext(6)  := S(Byte2(X3)) xor Byte2(Encrypt_Key(Index));
197      Ciphertext(7)  := S(Byte3(X0)) xor Byte3(Encrypt_Key(Index));
198
199      Index := Index+1;
200
201      Ciphertext(8)  := S(Byte0(X2)) xor Byte0(Encrypt_Key(Index));
202      Ciphertext(9)  := S(Byte1(X3)) xor Byte1(Encrypt_Key(Index));
203      Ciphertext(10) := S(Byte2(X0)) xor Byte2(Encrypt_Key(Index));
204      Ciphertext(11) := S(Byte3(X1)) xor Byte3(Encrypt_Key(Index));
205
206      Index := Index+1;
207
208      Ciphertext(12) := S(Byte0(X3)) xor Byte0(Encrypt_Key(Index));
209      Ciphertext(13) := S(Byte1(X0)) xor Byte1(Encrypt_Key(Index));
210      Ciphertext(14) := S(Byte2(X1)) xor Byte2(Encrypt_Key(Index));
211      Ciphertext(15) := S(Byte3(X2)) xor Byte3(Encrypt_Key(Index));
212
213      return Ciphertext;
214   end Encrypt;
215
216   -------------------------------------------------------------------------
217   -------------------------------------------------------------------------
218
219   procedure Encrypt128(Cipherkey  : in  Cipherkey_AES128;
220                        Plaintext  : in  B_Block128;
221                        Ciphertext : out B_Block128) is
222   begin
223      Ciphertext := Encrypt(Words(Cipherkey.Encrypt_Key), Plaintext);
224   end Encrypt128;
225
226   -------------------------------------------------------------------------
227
228   procedure Encrypt192(Cipherkey  : in  Cipherkey_AES192;
229                        Plaintext  : in  B_Block128;
230                        Ciphertext : out B_Block128) is
231   begin
232      Ciphertext := Encrypt(Words(Cipherkey.Encrypt_Key), Plaintext);
233   end Encrypt192;
234
235   -------------------------------------------------------------------------
236
237   procedure Encrypt256(Cipherkey  : in  Cipherkey_AES256;
238                        Plaintext  : in  B_Block128;
239                        Ciphertext : out B_Block128) is
240   begin
241      Ciphertext := Encrypt(Words(Cipherkey.Encrypt_Key), Plaintext);
242   end Encrypt256;
243
244
245   -------------------------------------------------------------------------
246   --------------------------DECRYPT----------------------------------------
247   -------------------------------------------------------------------------
248
249   function Decrypt(Decrypt_Key : in Words; Ciphertext : B_Block128)
250                   return B_Block128 is
251      Rounds : constant Positive := Decrypt_Key'Length/Nb-1;
252      Index : Natural:=Rounds*Nb;         -- current Decrypt_Key index
253      A0, A1, A2, A3 : Word;   -- working variables
254      X0, X1, X2, X3 : Word;   -- working variables
255      Plaintext : B_Block128;
256   begin
257
258      -- ciphertext To B_Block + key
259      X0 := To_Word(Ciphertext(0), Ciphertext(1), Ciphertext(2),
260                          Ciphertext(3))  xor Decrypt_Key(Index);
261      Index:= Index+1; -- Index := Rounds*Nb+1;
262      X1 := To_Word(Ciphertext(4), Ciphertext(5), Ciphertext(6),
263                          Ciphertext(7))   xor Decrypt_Key(Index);
264      Index:= Index+1; -- Index := Rounds*Nb+2;
265      X2 := To_Word(Ciphertext(8), Ciphertext(9), Ciphertext(10),
266                          Ciphertext(11)) xor Decrypt_Key(Index);
267      Index:= Index+1; -- Index := Rounds*Nb+3;
268      X3 := To_Word(Ciphertext(12), Ciphertext(13), Ciphertext(14),
269                          Ciphertext(15)) xor Decrypt_Key(Index);
270
271
272      for R in 1..Rounds-1 loop
273         Index:=(Rounds-R)*Nb;
274
275         A0 := (T5(Byte0(X0))  xor T6(Byte1(X3)) xor T7(Byte2(X2)) xor
276                T8(Byte3(X1))) xor Decrypt_Key(Index);
277
278         Index:= Index+1;
279
280         A1 := (T5(Byte0(X1))  xor T6(Byte1(X0)) xor T7(Byte2(X3)) xor
281                T8(Byte3(X2))) xor Decrypt_Key(Index);
282
283         Index:= Index+1;
284
285         A2 := (T5(Byte0(X2))  xor T6(Byte1(X1)) xor T7(Byte2(X0)) xor
286                T8(Byte3(X3))) xor Decrypt_Key(Index);
287
288         Index:= Index+1;
289
290         A3 := (T5(Byte0(X3))  xor T6(Byte1(X2)) xor T7(Byte2(X1)) xor
291                T8(Byte3(X0))) xor Decrypt_Key(Index);
292
293         X0 := A0;
294         X1 := A1;
295         X2 := A2;
296         X3 := A3;
297
298      end loop;
299
300      -- last round is special
301        Plaintext(0)  := Si(Byte0(X0)) xor Byte0(Decrypt_Key(0));
302        Plaintext(1)  := Si(Byte1(X3)) xor Byte1(Decrypt_Key(0));
303        Plaintext(2)  := Si(Byte2(X2)) xor Byte2(Decrypt_Key(0));
304        Plaintext(3)  := Si(Byte3(X1)) xor Byte3(Decrypt_Key(0));
305
306        Plaintext(4)  := Si(Byte0(X1)) xor Byte0(Decrypt_Key(1));
307        Plaintext(5)  := Si(Byte1(X0)) xor Byte1(Decrypt_Key(1));
308        Plaintext(6)  := Si(Byte2(X3)) xor Byte2(Decrypt_Key(1));
309        Plaintext(7)  := Si(Byte3(X2)) xor Byte3(Decrypt_Key(1));
310
311        Plaintext(8)  := Si(Byte0(X2)) xor Byte0(Decrypt_Key(2));
312        Plaintext(9)  := Si(Byte1(X1)) xor Byte1(Decrypt_Key(2));
313        Plaintext(10) := Si(Byte2(X0)) xor Byte2(Decrypt_Key(2));
314        Plaintext(11) := Si(Byte3(X3)) xor Byte3(Decrypt_Key(2));
315
316        Plaintext(12) := Si(Byte0(X3)) xor Byte0(Decrypt_Key(3));
317        Plaintext(13) := Si(Byte1(X2)) xor Byte1(Decrypt_Key(3));
318        Plaintext(14) := Si(Byte2(X1)) xor Byte2(Decrypt_Key(3));
319        Plaintext(15) := Si(Byte3(X0)) xor Byte3(Decrypt_Key(3));
320
321      return Plaintext;
322   end Decrypt;
323
324   -------------------------------------------------------------------------
325   -------------------------------------------------------------------------
326
327   procedure Decrypt128(Cipherkey  : in  Cipherkey_AES128;
328                        Ciphertext : in  B_Block128;
329                        Plaintext  : out B_Block128) is
330   begin
331      Plaintext := Decrypt(Words(Cipherkey.Decrypt_Key), Ciphertext);
332   end Decrypt128;
333
334   -------------------------------------------------------------------------
335
336   procedure Decrypt192(Cipherkey  : in  Cipherkey_AES192;
337                        Ciphertext : in  B_Block128;
338                        Plaintext  : out B_Block128) is
339   begin
340      Plaintext := Decrypt(Words(Cipherkey.Decrypt_Key), Ciphertext);
341   end Decrypt192;
342
343   -------------------------------------------------------------------------
344
345   procedure Decrypt256(Cipherkey  : in  Cipherkey_AES256;
346                        Ciphertext : in  B_Block128;
347                        Plaintext  : out B_Block128) is
348   begin
349      Plaintext := Decrypt(Words(Cipherkey.Decrypt_Key), Ciphertext);
350   end Decrypt256;
351
352end Crypto.Symmetric.Algorithm.AES;
353