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