001: // AesCipher - the AES encryption method
002: //
003: // Before being selected as the Advanced Encryption Standard this was
004: // known as Rijndael, and was designed by Joan Daemen and Vincent Rijmen.
005: // Most of the algorithm code is copyright by them. A few modifications
006: // to the algorithm, and the surrounding glue, are:
007: //
008: // Copyright (C) 1996,2000 by Jef Poskanzer <jef@acme.com>.
009: // All rights reserved.
010: //
011: // Redistribution and use in source and binary forms, with or without
012: // modification, are permitted provided that the following conditions
013: // are met:
014: // 1. Redistributions of source code must retain the above copyright
015: // notice, this list of conditions and the following disclaimer.
016: // 2. Redistributions in binary form must reproduce the above copyright
017: // notice, this list of conditions and the following disclaimer in the
018: // documentation and/or other materials provided with the distribution.
019: //
020: // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
021: // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
024: // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
025: // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
026: // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
027: // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
028: // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
029: // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
030: // SUCH DAMAGE.
031: //
032: // Visit the ACME Labs Java page for up-to-date versions of this and other
033: // fine Java utilities: http://www.acme.com/java/
034:
035: package Acme.Crypto;
036:
037: import java.io.*;
038:
039: /// The AES encryption method.
040: // <P>
041: // Before being selected as the Advanced Encryption Standard this was
042: // known as Rijndael, and was designed by Joan Daemen and Vincent Rijmen.
043: // <P>
044: // <A HREF="/resources/classes/Acme/Crypto/AesCipher.java">Fetch the software.</A><BR>
045: // <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
046: // <P>
047: // @see EncryptedOutputStream
048: // @see EncryptedInputStream
049:
050: public class AesCipher extends BlockCipher {
051:
052: // Constants, variables, and auxillary routines.
053:
054: // Key size in bytes. Valid values are 16, 24, and 32.
055: public static final int KEY_SIZE = 16;
056:
057: // Block size in bytes. Valid values are 16, 24, and 32.
058: public static final int BLOCK_SIZE = 16;
059:
060: private static final int[] alog = new int[256];
061: private static final int[] log = new int[256];
062:
063: private static final byte[] S = new byte[256];
064: private static final byte[] Si = new byte[256];
065: private static final int[] T1 = new int[256];
066: private static final int[] T2 = new int[256];
067: private static final int[] T3 = new int[256];
068: private static final int[] T4 = new int[256];
069: private static final int[] T5 = new int[256];
070: private static final int[] T6 = new int[256];
071: private static final int[] T7 = new int[256];
072: private static final int[] T8 = new int[256];
073: private static final int[] U1 = new int[256];
074: private static final int[] U2 = new int[256];
075: private static final int[] U3 = new int[256];
076: private static final int[] U4 = new int[256];
077: private static final byte[] rcon = new byte[30];
078:
079: static private final int[][][] shifts = new int[][][] {
080: { { 0, 0 }, { 1, 3 }, { 2, 2 }, { 3, 1 } },
081: { { 0, 0 }, { 1, 5 }, { 2, 4 }, { 3, 3 } },
082: { { 0, 0 }, { 1, 7 }, { 3, 5 }, { 4, 4 } } };
083:
084: private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4',
085: '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
086:
087: // Static initializer - to intialise S-boxes and T-boxes
088: static {
089: int ROOT = 0x11B;
090: int i, j = 0;
091:
092: // Produce log and alog tables, needed for multiplying in the
093: // field GF(2^m) (generator = 3).
094: alog[0] = 1;
095: for (i = 1; i < 256; ++i) {
096: j = (alog[i - 1] << 1) ^ alog[i - 1];
097: if ((j & 0x100) != 0)
098: j ^= ROOT;
099: alog[i] = j;
100: }
101: for (i = 1; i < 255; ++i)
102: log[alog[i]] = i;
103: byte[][] A = new byte[][] { { 1, 1, 1, 1, 1, 0, 0, 0 },
104: { 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 0, 1, 1, 1, 1, 1, 0 },
105: { 0, 0, 0, 1, 1, 1, 1, 1 }, { 1, 0, 0, 0, 1, 1, 1, 1 },
106: { 1, 1, 0, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 0, 0, 1, 1 },
107: { 1, 1, 1, 1, 0, 0, 0, 1 } };
108: byte[] B = new byte[] { 0, 1, 1, 0, 0, 0, 1, 1 };
109:
110: // Substitution box based on F^{-1}(x).
111: int t;
112: byte[][] box = new byte[256][8];
113: box[1][7] = 1;
114: for (i = 2; i < 256; ++i) {
115: j = alog[255 - log[i]];
116: for (t = 0; t < 8; ++t)
117: box[i][t] = (byte) ((j >>> (7 - t)) & 0x01);
118: }
119: // Affine transform: box[i] <- B + A*box[i].
120: byte[][] cox = new byte[256][8];
121: for (i = 0; i < 256; ++i)
122: for (t = 0; t < 8; ++t) {
123: cox[i][t] = B[t];
124: for (j = 0; j < 8; ++j)
125: cox[i][t] ^= A[t][j] * box[i][j];
126: }
127: // S-boxes and inverse S-boxes.
128: for (i = 0; i < 256; ++i) {
129: S[i] = (byte) (cox[i][0] << 7);
130: for (t = 1; t < 8; ++t)
131: S[i] ^= cox[i][t] << (7 - t);
132: Si[S[i] & 0xFF] = (byte) i;
133: }
134: // T-boxes.
135: byte[][] G = new byte[][] { { 2, 1, 1, 3 }, { 3, 2, 1, 1 },
136: { 1, 3, 2, 1 }, { 1, 1, 3, 2 } };
137: byte[][] AA = new byte[4][8];
138: for (i = 0; i < 4; ++i) {
139: for (j = 0; j < 4; ++j)
140: AA[i][j] = G[i][j];
141: AA[i][i + 4] = 1;
142: }
143: byte pivot, tmp;
144: byte[][] iG = new byte[4][4];
145: for (i = 0; i < 4; ++i) {
146: pivot = AA[i][i];
147: if (pivot == 0) {
148: t = i + 1;
149: while ((AA[t][i] == 0) && (t < 4))
150: ++t;
151: if (t == 4)
152: throw new RuntimeException(
153: "G matrix is not invertible");
154: else {
155: for (j = 0; j < 8; ++j) {
156: tmp = AA[i][j];
157: AA[i][j] = AA[t][j];
158: AA[t][j] = (byte) tmp;
159: }
160: pivot = AA[i][i];
161: }
162: }
163: for (j = 0; j < 8; ++j)
164: if (AA[i][j] != 0)
165: AA[i][j] = (byte) alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255];
166: for (t = 0; t < 4; ++t)
167: if (i != t) {
168: for (j = i + 1; j < 8; ++j)
169: AA[t][j] ^= mul(AA[i][j], AA[t][i]);
170: AA[t][i] = 0;
171: }
172: }
173: for (i = 0; i < 4; ++i)
174: for (j = 0; j < 4; ++j)
175: iG[i][j] = AA[i][j + 4];
176:
177: int s;
178: for (t = 0; t < 256; ++t) {
179: s = S[t];
180: T1[t] = mul4(s, G[0]);
181: T2[t] = mul4(s, G[1]);
182: T3[t] = mul4(s, G[2]);
183: T4[t] = mul4(s, G[3]);
184:
185: s = Si[t];
186: T5[t] = mul4(s, iG[0]);
187: T6[t] = mul4(s, iG[1]);
188: T7[t] = mul4(s, iG[2]);
189: T8[t] = mul4(s, iG[3]);
190:
191: U1[t] = mul4(t, iG[0]);
192: U2[t] = mul4(t, iG[1]);
193: U3[t] = mul4(t, iG[2]);
194: U4[t] = mul4(t, iG[3]);
195: }
196: // Round constants.
197: rcon[0] = 1;
198: int r = 1;
199: for (t = 1; t < 30;)
200: rcon[t++] = (byte) (r = mul(2, r));
201: }
202:
203: /// Multiply two elements of GF(2^m).
204: static final int mul(int a, int b) {
205: return (a != 0 && b != 0) ? alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
206: : 0;
207: }
208:
209: /// Convenience method used in generating Transposition boxes.
210: static final int mul4(int a, byte[] b) {
211: if (a == 0)
212: return 0;
213: a = log[a & 0xFF];
214: int a0 = (b[0] != 0) ? alog[(a + log[b[0] & 0xFF]) % 255] & 0xFF
215: : 0;
216: int a1 = (b[1] != 0) ? alog[(a + log[b[1] & 0xFF]) % 255] & 0xFF
217: : 0;
218: int a2 = (b[2] != 0) ? alog[(a + log[b[2] & 0xFF]) % 255] & 0xFF
219: : 0;
220: int a3 = (b[3] != 0) ? alog[(a + log[b[3] & 0xFF]) % 255] & 0xFF
221: : 0;
222: return a0 << 24 | a1 << 16 | a2 << 8 | a3;
223: }
224:
225: /// Return the number of rounds for a given Rijndael's key and block sizes.
226: // @param keySize The size of the user key material in bytes.
227: // @param blockSize The desired block size in bytes.
228: // @return The number of rounds for a given Rijndael's key and block sizes.
229: public static int getRounds(int keySize, int blockSize) {
230: switch (keySize) {
231: case 16:
232: return blockSize == 16 ? 10 : (blockSize == 24 ? 12 : 14);
233: case 24:
234: return blockSize != 32 ? 12 : 14;
235: default: // 32 bytes = 256 bits
236: return 14;
237: }
238: }
239:
240: // Constructors.
241:
242: // Constructor, string key.
243: public AesCipher(String keyStr) {
244: super (KEY_SIZE, BLOCK_SIZE);
245: setKey(keyStr);
246: }
247:
248: // Constructor, byte-array key.
249: public AesCipher(byte[] key) {
250: super (KEY_SIZE, BLOCK_SIZE);
251: setKey(key);
252: }
253:
254: // Key routines.
255:
256: private int ROUNDS = getRounds(KEY_SIZE, BLOCK_SIZE);
257: private int BC = BLOCK_SIZE / 4;
258: private int[][] Ke = new int[ROUNDS + 1][BC]; // encryption round keys
259: private int[][] Kd = new int[ROUNDS + 1][BC]; // decryption round keys
260:
261: /// Set the key.
262: public void setKey(byte[] key) {
263: if (key.length != KEY_SIZE)
264: throw new RuntimeException("Incorrect key length");
265: int ROUND_KEY_COUNT = (ROUNDS + 1) * BC;
266: int KC = KEY_SIZE / 4;
267: int[] tk = new int[KC];
268: int i, j;
269:
270: // Copy user material bytes into temporary ints.
271: for (i = 0, j = 0; i < KC;)
272: tk[i++] = (key[j++] & 0xFF) << 24 | (key[j++] & 0xFF) << 16
273: | (key[j++] & 0xFF) << 8 | (key[j++] & 0xFF);
274: // Copy values into round key arrays.
275: int t = 0;
276: for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); ++j, ++t) {
277: Ke[t / BC][t % BC] = tk[j];
278: Kd[ROUNDS - (t / BC)][t % BC] = tk[j];
279: }
280: int tt, rconpointer = 0;
281: while (t < ROUND_KEY_COUNT) {
282: // Extrapolate using phi (the round key evolution function).
283: tt = tk[KC - 1];
284: tk[0] ^= (S[(tt >>> 16) & 0xFF] & 0xFF) << 24
285: ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 16
286: ^ (S[tt & 0xFF] & 0xFF) << 8
287: ^ (S[(tt >>> 24) & 0xFF] & 0xFF)
288: ^ (rcon[rconpointer++] & 0xFF) << 24;
289: if (KC != 8)
290: for (i = 1, j = 0; i < KC;)
291: tk[i++] ^= tk[j++];
292: else {
293: for (i = 1, j = 0; i < KC / 2;)
294: tk[i++] ^= tk[j++];
295: tt = tk[KC / 2 - 1];
296: tk[KC / 2] ^= (S[tt & 0xFF] & 0xFF)
297: ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 8
298: ^ (S[(tt >>> 16) & 0xFF] & 0xFF) << 16
299: ^ (S[(tt >>> 24) & 0xFF] & 0xFF) << 24;
300: for (j = KC / 2, i = j + 1; i < KC;)
301: tk[i++] ^= tk[j++];
302: }
303: // Copy values into round key arrays.
304: for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); ++j, ++t) {
305: Ke[t / BC][t % BC] = tk[j];
306: Kd[ROUNDS - (t / BC)][t % BC] = tk[j];
307: }
308: }
309: for (int r = 1; r < ROUNDS; ++r)
310: // inverse MixColumn where needed
311: for (j = 0; j < BC; ++j) {
312: tt = Kd[r][j];
313: Kd[r][j] = U1[(tt >>> 24) & 0xFF]
314: ^ U2[(tt >>> 16) & 0xFF]
315: ^ U3[(tt >>> 8) & 0xFF] ^ U4[tt & 0xFF];
316: }
317: }
318:
319: // Block encryption routines.
320:
321: private int[] tempInts = new int[8];
322:
323: /// Encrypt a block.
324: public void encrypt(byte[] clearText, int clearOff,
325: byte[] cipherText, int cipherOff) {
326: int SC = (BC == 4 ? 0 : (BC == 6 ? 1 : 2));
327: int s1 = shifts[SC][1][0];
328: int s2 = shifts[SC][2][0];
329: int s3 = shifts[SC][3][0];
330: int[] a = new int[BC];
331: int[] t = new int[BC]; // temporary work array
332: int i;
333: int tt;
334:
335: for (i = 0; i < BC; ++i)
336: // plaintext to ints + key
337: t[i] = ((clearText[clearOff++] & 0xFF) << 24
338: | (clearText[clearOff++] & 0xFF) << 16
339: | (clearText[clearOff++] & 0xFF) << 8 | (clearText[clearOff++] & 0xFF))
340: ^ Ke[0][i];
341: // Apply round transforms.
342: for (int r = 1; r < ROUNDS; ++r) {
343: for (i = 0; i < BC; ++i)
344: a[i] = (T1[(t[i] >>> 24) & 0xFF]
345: ^ T2[(t[(i + s1) % BC] >>> 16) & 0xFF]
346: ^ T3[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ T4[t[(i + s3)
347: % BC] & 0xFF])
348: ^ Ke[r][i];
349: System.arraycopy(a, 0, t, 0, BC);
350: }
351: // Last round is special.
352: for (i = 0; i < BC; ++i) {
353: tt = Ke[ROUNDS][i];
354: cipherText[cipherOff++] = (byte) (S[(t[i] >>> 24) & 0xFF] ^ (tt >>> 24));
355: cipherText[cipherOff++] = (byte) (S[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16));
356: cipherText[cipherOff++] = (byte) (S[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8));
357: cipherText[cipherOff++] = (byte) (S[t[(i + s3) % BC] & 0xFF] ^ tt);
358: }
359: }
360:
361: /// Decrypt a block.
362: public void decrypt(byte[] cipherText, int cipherOff,
363: byte[] clearText, int clearOff) {
364: int SC = (BC == 4 ? 0 : (BC == 6 ? 1 : 2));
365: int s1 = shifts[SC][1][1];
366: int s2 = shifts[SC][2][1];
367: int s3 = shifts[SC][3][1];
368: int[] a = new int[BC];
369: int[] t = new int[BC]; // temporary work array
370: int i;
371: int tt;
372:
373: for (i = 0; i < BC; ++i)
374: // ciphertext to ints + key
375: t[i] = ((cipherText[cipherOff++] & 0xFF) << 24
376: | (cipherText[cipherOff++] & 0xFF) << 16
377: | (cipherText[cipherOff++] & 0xFF) << 8 | (cipherText[cipherOff++] & 0xFF))
378: ^ Kd[0][i];
379: // Apply round transforms.
380: for (int r = 1; r < ROUNDS; ++r) {
381: for (i = 0; i < BC; ++i)
382: a[i] = (T5[(t[i] >>> 24) & 0xFF]
383: ^ T6[(t[(i + s1) % BC] >>> 16) & 0xFF]
384: ^ T7[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ T8[t[(i + s3)
385: % BC] & 0xFF])
386: ^ Kd[r][i];
387: System.arraycopy(a, 0, t, 0, BC);
388: }
389: // Last round is special.
390: for (i = 0; i < BC; ++i) {
391: tt = Kd[ROUNDS][i];
392: clearText[clearOff++] = (byte) (Si[(t[i] >>> 24) & 0xFF] ^ (tt >>> 24));
393: clearText[clearOff++] = (byte) (Si[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16));
394: clearText[clearOff++] = (byte) (Si[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8));
395: clearText[clearOff++] = (byte) (Si[t[(i + s3) % BC] & 0xFF] ^ tt);
396: }
397: }
398:
399: /// Test routine.
400: public static void main(String[] args) {
401: byte[] cipherText = new byte[16];
402: byte[] decipherText = new byte[16];
403:
404: BlockCipher aesa = new AesCipher("0123456789");
405: byte[] clearText1 = { (byte) 0x00, (byte) 0x00, (byte) 0x00,
406: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
407: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
408: (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
409: (byte) 0x00 };
410: System.out.println("cleartext: " + toStringBlock(clearText1));
411: aesa.encrypt(clearText1, cipherText);
412: System.out.println("encrypted: " + toStringBlock(cipherText));
413: aesa.decrypt(cipherText, decipherText);
414: System.out.println("decrypted: " + toStringBlock(decipherText));
415:
416: System.out.println();
417:
418: BlockCipher aesb = new AesCipher("abcdefghijklmnopqrstuvwxyz");
419: byte[] clearText2 = { (byte) 0x00, (byte) 0x01, (byte) 0x02,
420: (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06,
421: (byte) 0x07, (byte) 0x08, (byte) 0x09, (byte) 0x0a,
422: (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e,
423: (byte) 0x0f };
424: System.out.println("cleartext: " + toStringBlock(clearText2));
425: aesb.encrypt(clearText2, cipherText);
426: System.out.println("encrypted: " + toStringBlock(cipherText));
427: aesb.decrypt(cipherText, decipherText);
428: System.out.println("decrypted: " + toStringBlock(decipherText));
429: }
430:
431: }
|