minor cleanup, encodefile command in Base64.java
[org.ibex.crypto.git] / src / org / ibex / crypto / AES.java
1 /* Copyright (c) 2000 The Legion Of The Bouncy Castle 
2 * (http://www.bouncycastle.org)
3
4 * Permission is hereby granted, free of charge, to any person obtaining a 
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation 
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
8 * and/or sell copies of the Software, and to permit persons to whom the 
9 * Software is furnished to do so, subject to the following conditions:
10
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDER.S BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
20 * DEALINGS IN THE SOFTWARE.
21 */
22 package org.ibex.crypto;
23
24 public class AES implements Cipher {
25     public AES(byte[] k, boolean reverse) {
26         this.forEncryption = !reverse;
27         WorkingKey = generateWorkingKey(k,forEncryption);
28     }
29     
30     public void process(byte[] in, int inp, byte[] out, int outp, int len) {
31         if((len % 16) != 0) throw new IllegalArgumentException("buffer must be a multiple of block size");
32         while(len != 0) {
33             unpackBlock(in,inp);
34             if(forEncryption) encryptBlock(WorkingKey);
35             else decryptBlock(WorkingKey);
36             packBlock(out,outp);
37             inp += 16; outp+=16; len-=16;
38         }
39     }
40     
41     // everything below if from BouncyCastle
42     
43     /**
44      * an implementation of the AES (Rijndael), from FIPS-197.
45      * <p>
46      * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
47      *
48      * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
49      * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
50      *
51      * There are three levels of tradeoff of speed vs memory
52      * Because java has no preprocessor, they are written as three separate classes from which to choose
53      *
54      * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
55      * and 4 for decryption.
56      *
57      * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
58      * adding 12 rotate operations per round to compute the values contained in the other tables from
59      * the contents of the first
60      *
61      * The slowest version uses no static tables at all and computes the values
62      * in each round.
63      * <p>
64      * This file contains the slowest performance version with no static tables
65      * for round precomputation, but it has the smallest foot print.
66      *
67      */
68     
69     // The S box
70     private static final byte[] S = {
71         (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
72         (byte)48,   (byte)1, (byte)103,  (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
73         (byte)202, (byte)130, (byte)201, (byte)125, (byte)250,  (byte)89,  (byte)71, (byte)240,
74         (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
75         (byte)183, (byte)253, (byte)147,  (byte)38,  (byte)54,  (byte)63, (byte)247, (byte)204,
76         (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216,  (byte)49,  (byte)21,
77         (byte)4, (byte)199,  (byte)35, (byte)195,  (byte)24, (byte)150,   (byte)5, (byte)154,
78         (byte)7,  (byte)18, (byte)128, (byte)226, (byte)235,  (byte)39, (byte)178, (byte)117,
79         (byte)9, (byte)131,  (byte)44,  (byte)26,  (byte)27, (byte)110,  (byte)90, (byte)160,
80         (byte)82,  (byte)59, (byte)214, (byte)179,  (byte)41, (byte)227,  (byte)47, (byte)132,
81         (byte)83, (byte)209,   (byte)0, (byte)237,  (byte)32, (byte)252, (byte)177,  (byte)91,
82         (byte)106, (byte)203, (byte)190,  (byte)57,  (byte)74,  (byte)76,  (byte)88, (byte)207,
83         (byte)208, (byte)239, (byte)170, (byte)251,  (byte)67,  (byte)77,  (byte)51, (byte)133,
84         (byte)69, (byte)249,   (byte)2, (byte)127,  (byte)80,  (byte)60, (byte)159, (byte)168,
85         (byte)81, (byte)163,  (byte)64, (byte)143, (byte)146, (byte)157,  (byte)56, (byte)245,
86         (byte)188, (byte)182, (byte)218,  (byte)33,  (byte)16, (byte)255, (byte)243, (byte)210,
87         (byte)205,  (byte)12,  (byte)19, (byte)236,  (byte)95, (byte)151,  (byte)68,  (byte)23,
88         (byte)196, (byte)167, (byte)126,  (byte)61, (byte)100,  (byte)93,  (byte)25, (byte)115,
89         (byte)96, (byte)129,  (byte)79, (byte)220,  (byte)34,  (byte)42, (byte)144, (byte)136,
90         (byte)70, (byte)238, (byte)184,  (byte)20, (byte)222,  (byte)94,  (byte)11, (byte)219,
91         (byte)224,  (byte)50,  (byte)58,  (byte)10,  (byte)73,   (byte)6,  (byte)36,  (byte)92,
92         (byte)194, (byte)211, (byte)172,  (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
93         (byte)231, (byte)200,  (byte)55, (byte)109, (byte)141, (byte)213,  (byte)78, (byte)169,
94         (byte)108,  (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174,   (byte)8,
95         (byte)186, (byte)120,  (byte)37,  (byte)46,  (byte)28, (byte)166, (byte)180, (byte)198,
96         (byte)232, (byte)221, (byte)116,  (byte)31,  (byte)75, (byte)189, (byte)139, (byte)138,
97         (byte)112,  (byte)62, (byte)181, (byte)102,  (byte)72,   (byte)3, (byte)246,  (byte)14,
98         (byte)97,  (byte)53,  (byte)87, (byte)185, (byte)134, (byte)193,  (byte)29, (byte)158,
99         (byte)225, (byte)248, (byte)152,  (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
100         (byte)155,  (byte)30, (byte)135, (byte)233, (byte)206,  (byte)85,  (byte)40, (byte)223,
101         (byte)140, (byte)161, (byte)137,  (byte)13, (byte)191, (byte)230,  (byte)66, (byte)104,
102         (byte)65, (byte)153,  (byte)45,  (byte)15, (byte)176,  (byte)84, (byte)187,  (byte)22
103     };
104     
105     // The inverse S-box
106     private static final byte[] Si = {
107         (byte)82,   (byte)9, (byte)106, (byte)213,  (byte)48,  (byte)54, (byte)165,  (byte)56,
108         (byte)191,  (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
109         (byte)124, (byte)227,  (byte)57, (byte)130, (byte)155,  (byte)47, (byte)255, (byte)135,
110         (byte)52, (byte)142,  (byte)67,  (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
111         (byte)84, (byte)123, (byte)148,  (byte)50, (byte)166, (byte)194,  (byte)35,  (byte)61,
112         (byte)238,  (byte)76, (byte)149,  (byte)11,  (byte)66, (byte)250, (byte)195,  (byte)78,
113         (byte)8,  (byte)46, (byte)161, (byte)102,  (byte)40, (byte)217,  (byte)36, (byte)178,
114         (byte)118,  (byte)91, (byte)162,  (byte)73, (byte)109, (byte)139, (byte)209,  (byte)37,
115         (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152,  (byte)22,
116         (byte)212, (byte)164,  (byte)92, (byte)204,  (byte)93, (byte)101, (byte)182, (byte)146,
117         (byte)108, (byte)112,  (byte)72,  (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
118         (byte)94,  (byte)21,  (byte)70,  (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
119         (byte)144, (byte)216, (byte)171,   (byte)0, (byte)140, (byte)188, (byte)211,  (byte)10,
120         (byte)247, (byte)228,  (byte)88,   (byte)5, (byte)184, (byte)179,  (byte)69,   (byte)6,
121         (byte)208,  (byte)44,  (byte)30, (byte)143, (byte)202,  (byte)63,  (byte)15,   (byte)2,
122         (byte)193, (byte)175, (byte)189,   (byte)3,   (byte)1,  (byte)19, (byte)138, (byte)107,
123         (byte)58, (byte)145,  (byte)17,  (byte)65,  (byte)79, (byte)103, (byte)220, (byte)234,
124         (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
125         (byte)150, (byte)172, (byte)116,  (byte)34, (byte)231, (byte)173,  (byte)53, (byte)133,
126         (byte)226, (byte)249,  (byte)55, (byte)232,  (byte)28, (byte)117, (byte)223, (byte)110,
127         (byte)71, (byte)241,  (byte)26, (byte)113,  (byte)29,  (byte)41, (byte)197, (byte)137,
128         (byte)111, (byte)183,  (byte)98,  (byte)14, (byte)170,  (byte)24, (byte)190,  (byte)27,
129         (byte)252,  (byte)86,  (byte)62,  (byte)75, (byte)198, (byte)210, (byte)121,  (byte)32,
130         (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205,  (byte)90, (byte)244,
131         (byte)31, (byte)221, (byte)168,  (byte)51, (byte)136,   (byte)7, (byte)199,  (byte)49,
132         (byte)177,  (byte)18,  (byte)16,  (byte)89,  (byte)39, (byte)128, (byte)236,  (byte)95,
133         (byte)96,  (byte)81, (byte)127, (byte)169,  (byte)25, (byte)181,  (byte)74,  (byte)13,
134         (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
135         (byte)160, (byte)224,  (byte)59,  (byte)77, (byte)174,  (byte)42, (byte)245, (byte)176,
136         (byte)200, (byte)235, (byte)187,  (byte)60, (byte)131,  (byte)83, (byte)153,  (byte)97,
137         (byte)23,  (byte)43,   (byte)4, (byte)126, (byte)186, (byte)119, (byte)214,  (byte)38,
138         (byte)225, (byte)105,  (byte)20,  (byte)99,  (byte)85,  (byte)33,  (byte)12, (byte)125
139     };
140     
141     // vector used in calculating key schedule (powers of x in GF(256))
142     private static final int[] rcon = {
143         0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
144         0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
145     
146     private int shift(
147                       int     r,
148                       int     shift)
149     {
150         return (((r >>> shift) | (r << (32 - shift))));
151     }
152     
153     /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
154     
155     private static final int m1 = 0x80808080;
156     private static final int m2 = 0x7f7f7f7f;
157     private static final int m3 = 0x0000001b;
158     
159     private int FFmulX(int x)
160     {
161         return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
162     }
163     
164     /* 
165         The following defines provide alternative definitions of FFmulX that might
166      give improved performance if a fast 32-bit multiply is not available.
167      
168      private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } 
169      private static final int  m4 = 0x1b1b1b1b;
170      private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } 
171      
172      */
173     
174     private int mcol(int x)
175     {
176         int f2 = FFmulX(x);
177         return f2 ^ shift(x ^ f2, 8) ^ shift(x, 16) ^ shift(x, 24);
178     }
179     
180     private int inv_mcol(int x)
181     {
182         int f2 = FFmulX(x);
183         int f4 = FFmulX(f2);
184         int f8 = FFmulX(f4);
185         int f9 = x ^ f8;
186         
187         return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24);
188     }
189     
190     
191     private int subWord(int x)
192     {
193         return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
194     }
195     
196     /**
197         * Calculate the necessary round keys
198      * The number of calculations depends on key size and block size
199      * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
200      * This code is written assuming those are the only possible values
201      */
202     private int[][] generateWorkingKey(
203                                        byte[] key,
204                                        boolean forEncryption)
205     {
206         int         KC = key.length / 4;  // key length in words
207         int         t;
208         
209         if ((KC != 4) && (KC != 6) && (KC != 8)) {
210             throw new IllegalArgumentException("Key length not 128/192/256 bits.");
211         }
212         
213         ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
214         int[][] W = new int[ROUNDS+1][4];   // 4 words in a block
215         
216         //
217         // copy the key into the round key array
218         //
219         
220         t = 0;
221         for (int i = 0; i < key.length; t++)
222         {
223             W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
224             i+=4;
225         }
226         
227         //
228         // while not enough round key material calculated
229         // calculate new values
230         //
231         int k = (ROUNDS + 1) << 2;
232         for (int i = KC; (i < k); i++)
233         {
234             int temp = W[(i-1)>>2][(i-1)&3];
235             if ((i % KC) == 0) {
236                 temp = subWord(shift(temp, 8)) ^ rcon[(i / KC)-1];
237             } else if ((KC > 6) && ((i % KC) == 4)) {
238                 temp = subWord(temp);
239             }
240             
241             W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
242         }
243         
244         if (!forEncryption) {
245             for (int j = 1; j < ROUNDS; j++) {
246                 for (int i = 0; i < 4; i++){
247                     W[j][i] = inv_mcol(W[j][i]);
248                 }
249             }
250         }
251         
252         return W;
253     }
254     
255     private int         ROUNDS;
256     private int[][] WorkingKey = null;
257     private int         C0, C1, C2, C3;
258     private boolean     forEncryption;
259     
260     private final void unpackBlock(
261                                    byte[]      bytes,
262                                    int         off)
263     {
264         int     index = off;
265         
266         C0 = (bytes[index++] & 0xff);
267         C0 |= (bytes[index++] & 0xff) << 8;
268         C0 |= (bytes[index++] & 0xff) << 16;
269         C0 |= bytes[index++] << 24;
270         
271         C1 = (bytes[index++] & 0xff);
272         C1 |= (bytes[index++] & 0xff) << 8;
273         C1 |= (bytes[index++] & 0xff) << 16;
274         C1 |= bytes[index++] << 24;
275         
276         C2 = (bytes[index++] & 0xff);
277         C2 |= (bytes[index++] & 0xff) << 8;
278         C2 |= (bytes[index++] & 0xff) << 16;
279         C2 |= bytes[index++] << 24;
280         
281         C3 = (bytes[index++] & 0xff);
282         C3 |= (bytes[index++] & 0xff) << 8;
283         C3 |= (bytes[index++] & 0xff) << 16;
284         C3 |= bytes[index++] << 24;
285     }
286     
287     private final void packBlock(
288                                  byte[]      bytes,
289                                  int         off)
290     {
291         int     index = off;
292         
293         bytes[index++] = (byte)C0;
294         bytes[index++] = (byte)(C0 >> 8);
295         bytes[index++] = (byte)(C0 >> 16);
296         bytes[index++] = (byte)(C0 >> 24);
297         
298         bytes[index++] = (byte)C1;
299         bytes[index++] = (byte)(C1 >> 8);
300         bytes[index++] = (byte)(C1 >> 16);
301         bytes[index++] = (byte)(C1 >> 24);
302         
303         bytes[index++] = (byte)C2;
304         bytes[index++] = (byte)(C2 >> 8);
305         bytes[index++] = (byte)(C2 >> 16);
306         bytes[index++] = (byte)(C2 >> 24);
307         
308         bytes[index++] = (byte)C3;
309         bytes[index++] = (byte)(C3 >> 8);
310         bytes[index++] = (byte)(C3 >> 16);
311         bytes[index++] = (byte)(C3 >> 24);
312     }
313     
314     private void encryptBlock(int[][] KW)
315     {
316         int r, r0, r1, r2, r3;
317         
318         C0 ^= KW[0][0];
319         C1 ^= KW[0][1];
320         C2 ^= KW[0][2];
321         C3 ^= KW[0][3];
322         
323         for (r = 1; r < ROUNDS - 1;) {
324             r0 = mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r][0];
325             r1 = mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r][1];
326             r2 = mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r][2];
327             r3 = mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++][3];
328             C0 = mcol((S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24)) ^ KW[r][0];
329             C1 = mcol((S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24)) ^ KW[r][1];
330             C2 = mcol((S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24)) ^ KW[r][2];
331             C3 = mcol((S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24)) ^ KW[r++][3];
332         }
333         
334         r0 = mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r][0];
335         r1 = mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r][1];
336         r2 = mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r][2];
337         r3 = mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++][3];
338         
339         // the final round is a simple function of S
340         
341         C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
342         C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
343         C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
344         C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
345         
346     }
347     
348     private final void decryptBlock(int[][] KW)
349     {
350         int r, r0, r1, r2, r3;
351         
352         C0 ^= KW[ROUNDS][0];
353         C1 ^= KW[ROUNDS][1];
354         C2 ^= KW[ROUNDS][2];
355         C3 ^= KW[ROUNDS][3];
356         
357         for (r = ROUNDS-1; r>1;) {
358             r0 = inv_mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r][0];
359             r1 = inv_mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r][1];
360             r2 = inv_mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r][2];
361             r3 = inv_mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r--][3];
362             C0 = inv_mcol((Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24)) ^ KW[r][0];
363             C1 = inv_mcol((Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24)) ^ KW[r][1];
364             C2 = inv_mcol((Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24)) ^ KW[r][2];
365             C3 = inv_mcol((Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24)) ^ KW[r--][3];
366         }
367         
368         r0 = inv_mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r][0];
369         r1 = inv_mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r][1];
370         r2 = inv_mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r][2];
371         r3 = inv_mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r--][3];
372         
373         // the final round's table is a simple function of Si
374         
375         C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
376         C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
377         C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
378         C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
379     }    
380 }