Full Source Code AES_java
/** * Java AES implementation which takes a 128-, 192- or 256-bit key and encrypts * or decrypts the given text. * * @author David Young dayoung@csupomona.edu * */ public class AES implements AbstractAES { /** * The index of the current state in this AES cipher. */ protected int current; /** * The inverse S-Box substitution table. */ protected static final int[] invSBox = new int[] { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; /** * Rcon */ protected static final int[] rCon = new int[] { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb }; /** * The number of 32-bit words comprising the plaintext and columns comprising * the state matrix of an AES cipher. */ protected static int Nb = 4; /** * The number of 32-bit words comprising the cipher key in this AES cipher. */ protected int Nk; /** * The number of rounds in this AES cipher. */ protected int Nr; /** * The state matrices in this AES cipher. */ protected int[][][] s; /** * The S-Box substitution table. */ protected static final int[] sBox = new int[] { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; /** * The key schedule in this AES cipher. */ protected int[] w; /** * The cipher key. */ protected int[] key; /** * Constructs an AES cipher using a specific key. * * @param input * A 128-, 192- or 256-bit (i.e. 16-, 24- or 32-byte) secret key. * @throws IllegalArgumentException * if unknown key size is passed. */ public AES(byte[] input) { key = new int[input.length]; for (int i = 0; i < input.length; i++) { key[i] = input[i]; } Nb = 4; // Nb is 4 for AES standard but other values could be used. switch (input.length) { // 128 bit key. case 16: Nr = 10; Nk = 4; break; // 192 bit key. case 24: Nr = 12; Nk = 6; break; // 256 bit key. case 32: Nr = 14; Nk = 8; break; default: throw new IllegalArgumentException( "Only 128, 192, 256 keys are supported"); } // create storage for states. // only needs 2 states with 4 rows and Nb columns. s = new int[2][4][Nb]; // create storage for expanded key. w = new int[Nb * (Nr + 1)]; // expand key into array w. keyExpand(); } /** * Protected constructor. Needed for unit tests. */ protected AES() { } /** * Adds the key schedule for a round to a state matrix. * * @param s * A state matrix having Nb columns and 4 rows. * @param round * A round of the key schedule w to be added. * @return s, after adding the key schedule for round. */ protected int[][] addRoundKey(int[][] s, int round) { int temp; for (int c = 0; c < Nb; c++) { for (int r = 0; r < 4; r++) { s[r]1 = s[r]1 ^ ((w[round * Nb + c] << (r * 8)) >>> 24); } } return s; } /** * Encrypts the cipher text. * * @param in * array of text to encrypt * @param out * array to store the encrypted text * @return out */ protected int[][] cipher(int[][] in, int[][] out) { for (int i = 0; i < in.length; i++) { for (int j = 0; j < in[0].length; j++) { out[i][j] = in[i][j]; } } current = 0; // set round to 0; addRoundKey(out, current); for (current = 1; current < Nr; current++) { subBytes(out); shiftRows(out); mixColumns(out); addRoundKey(out, current); } subBytes(out); shiftRows(out); addRoundKey(out, current); return out; } /** * Decrypts the cipher text. * * @param in * array of encrypted text to decrypt * @param out * array to store the decrypted text * @return out */ protected int[][] invCipher(int[][] in, int[][] out) { for (int i = 0; i < in.length; i++) { for (int j = 0; j < in[0].length; j++) { out[i][j] = in[i][j]; } } current = Nr; addRoundKey(out, current); for (current = Nr - 1; current > 0; current--) { invShiftRows(out); invSubBytes(out); addRoundKey(out, current); invMixColumns(out); } invShiftRows(out); invSubBytes(out); addRoundKey(out, current); return out; } /** * (non-Javadoc) * * @see AbstractAES#decrypt(byte[]) */ @Override public byte[] decrypt(byte[] y) { if (y.length != 16) { throw new IllegalArgumentException("Can only decrypt 16byte arrays"); } byte[] storage = new byte[y.length]; for (int i = 0; i < Nb; i++) { // columns for (int j = 0; j < 4; j++) { // rows s[0][j][i] = y[i * Nb + j] & 0xff; } } // decypt into s[2] invCipher(s[0], s[1]); for (int i = 0; i < Nb; i++) { for (int j = 0; j < 4; j++) { storage[i * Nb + j] = (byte) (s[1][j][i] & 0xff); } } return storage; } /** * (non-Javadoc) * * @see AbstractAES#encrypt(byte[]) */ @Override public byte[] encrypt(byte[] x) { if (x.length != 16) { throw new IllegalArgumentException("Can only encrypt 16byte arrays"); } byte[] storage = new byte[x.length]; for (int i = 0; i < Nb; i++) { // colums for (int j = 0; j < 4; j++) { // rows s[0][j][i] = x[i * Nb + j] & 0xff; } } // encypt into s[2] cipher(s[0], s[1]); for (int i = 0; i < Nb; i++) { for (int j = 0; j < 4; j++) { storage[i * Nb + j] = (byte) (s[1][j][i] & 0xff); } } return storage; } /** * Unmixes each column of a state matrix. Multiplies each column--a polynomial * in GF(GF(2^8)^4)--times {0b}x^3+{0d}^2+{09}x+{0e} modulo x^4+1. * * @param s * A state matrix having Nb columns and 4 rows. * @return s, after unmixing each column. */ protected int[][] invMixColumns(int[][] s) { int temp0, temp1, temp2, temp3; // temps used to allow in place mix columns. // declared locally for principle of cohesion. for (int c = 0; c < Nb; c++) { // matrix multiplied with column of text. temp0 = mult(0x0e, s[0]1) ^ mult(0x0b, s[1]1) ^ mult(0x0d, s[2]1) ^ mult(0x09, s[3]1); temp1 = mult(0x09, s[0]1) ^ mult(0x0e, s[1]1) ^ mult(0x0b, s[2]1) ^ mult(0x0d, s[3]1); temp2 = mult(0x0d, s[0]1) ^ mult(0x09, s[1]1) ^ mult(0x0e, s[2]1) ^ mult(0x0b, s[3]1); temp3 = mult(0x0b, s[0]1) ^ mult(0x0d, s[1]1) ^ mult(0x09, s[2]1) ^ mult(0x0e, s[3]1); s[0]1 = temp0; s[1]1 = temp1; s[2]1 = temp2; s[3]1 = temp3; } return s; } /** * Applies an inverse cyclic shift to the last 3 rows of a state matrix. * * @param s * A state matrix having Nb columns and 4 rows. * @return s, after an inverse cyclic shift is applied to each row. */ protected int[][] invShiftRows(int[][] s) { int temp1, temp2, temp3, i; // temps used to allow in place shift rows. // declared locally for principle of cohesion. // skip row 0 // row 1 temp1 = s[1][Nb - 1]; for (i = Nb - 1; i > 0; i--) { s[1][i] = s[1][(i - 1) % Nb]; } s[1][0] = temp1; // row 2 temp1 = s[2][Nb - 1]; temp2 = s[2][Nb - 2]; for (i = Nb - 1; i > 1; i--) { s[2][i] = s[2][(i - 2) % Nb]; } s[2][1] = temp1; s[2][0] = temp2; // row 3 temp1 = s[3][Nb - 3]; temp2 = s[3][Nb - 2]; temp3 = s[3][Nb - 1]; for (i = Nb - 1; i > 2; i--) { s[3][i] = s[3][(i - 3) % Nb]; } s[3][0] = temp1; s[3][1] = temp2; s[3][2] = temp3; return s; } /** * Applies inverse S-Box substitution to each byte of a state matrix. * * @param s * A state matrix having Nb columns and 4 rows. * @return s, after inverse S-box substitution is applied to each byte. */ protected int[][] invSubBytes(int[][] s) { for (int i = 0; i < 4; i++) { for (int j = 0; j < Nb; j++) { s[i][j] = invSubWord(s[i][j]) & 0xFF; ; } } return s; } /** * Applies inverse S-box substitution to each byte of a 4-byte word. * * @param w * A 4-byte word. * @return w, after inverse S-box substitution is applied to each byte. */ protected static int invSubWord(int w) { int subWord = 0; for (int i = 24; i >= 0; i -= 8) { int in = w << i >>> 24; subWord |= invSBox[in] << (24 - i); } return subWord; } protected int[] keyExpand() { int temp, i = 0; while (i < Nk) { w[i] = 0x00000000; w[i] |= key[4 * i] << 24; w[i] |= key[4 * i + 1] << 16; w[i] |= key[4 * i + 2] << 8; w[i] |= key[4 * i + 3]; i++; } i = Nk; while (i < Nb * (Nr + 1)) { temp = w[i - 1]; if (i % Nk == 0) { temp = subWord(rotWord(temp)) ^ (rCon[i / Nk] << 24); } else if (Nk > 6 && (i % Nk == 4)) { temp = subWord(temp); } else { } w[i] = w[i - Nk] ^ temp; i++; } return w; } /** * Mixes each column of a state matrix. Multiplies each column--a polynomial * in GF(GF(2^8)^4)--times {03}x^3+{01}x^2+{01}x+{02} modulo x^4+1. * * @param s * A state matrix having Nb columns and 4 rows. * @return s, after mixing each column. */ protected int[][] mixColumns(int[][] s) { int temp0, temp1, temp2, temp3; for (int c = 0; c < Nb; c++) { temp0 = mult(0x02, s[0]1) ^ mult(0x03, s[1]1) ^ s[2]1 ^ s[3]1; temp1 = s[0]1 ^ mult(0x02, s[1]1) ^ mult(0x03, s[2]1) ^ s[3]1; temp2 = s[0]1 ^ s[1]1 ^ mult(0x02, s[2]1) ^ mult(0x03, s[3]1); temp3 = mult(0x03, s[0]1) ^ s[1]1 ^ s[2]1 ^ mult(0x02, s[3]1); s[0]1 = temp0; s[1]1 = temp1; s[2]1 = temp2; s[3]1 = temp3; } return s; } /** * Multiplies two polynomials a(x), b(x) in GF(2^8) modulo the irreducible * polynomial m(x) = x^8+x^4+x^3+x+1. (i.e. m(x) = 0x11b). * * @param a * A polynomial a(x) = a7x^7+a6x^6+a5x^5+a4x^4+a3x^3+a2x^2+a1x+a0 in * GF(2^8). * @param b * A polynomial b(x) = b7x^7+b6x^6+b5x^5+b4x^4+b3x^3+b2x^2+b1x+b0 in * GF(2^8). * @return a(x)b(x) modulo x^8+x^4+x^3+x+1. */ protected static int mult(int a, int b) { int sum = 0; while (a != 0) { // while a is not 0 if ((a & 1) != 0) // check if first bit is a 1 sum = sum ^ b; // add b to sum since lowest bit was 1 b = xtime(b); // bit shift left mod 0x11b if necessary; a = a >>> 1; // lowest bit of a was used so shift right } return sum; } /** * Applies a cyclic permutation to a 4-byte word. * * @param w * A 4-byte word. * @return w, after cyclic permutation is applied. */ protected static int rotWord(int w) { return (w << 8) | ((w & 0xFF000000) >>> 24); } /** * Applies a cyclic shift to the last 3 rows of a state matrix. * * @param s * A state matrix having Nb columns and 4 rows. * @return s, after a cyclic shift is applied to each row. */ protected int[][] shiftRows(int[][] s) { int temp1, temp2, temp3, i; // skip row 0 // row 1 temp1 = s[1][0]; for (i = 0; i < Nb - 1; i++) { s[1][i] = s[1][(i + 1) % Nb]; } s[1][Nb - 1] = temp1; // row 2 temp1 = s[2][0]; temp2 = s[2][1]; for (i = 0; i < Nb - 2; i++) { s[2][i] = s[2][(i + 2) % Nb]; } s[2][Nb - 2] = temp1; s[2][Nb - 1] = temp2; // row 3 temp1 = s[3][0]; temp2 = s[3][1]; temp3 = s[3][2]; for (i = 0; i < Nb - 3; i++) { s[3][i] = s[3][(i + 3) % Nb]; } s[3][Nb - 3] = temp1; s[3][Nb - 2] = temp2; s[3][Nb - 1] = temp3; return s; } /** * Applies S-Box substitution to each byte of a state matrix. * * @param s * A state matrix having Nb columns and 4 rows. * @return s, after S-box substitution is applied to each byte. */ protected int[][] subBytes(int[][] s) { for (int i = 0; i < 4; i++) { for (int j = 0; j < Nb; j++) { s[i][j] = subWord(s[i][j]) & 0xFF; } } return s; } /** * Applies S-box substitution to each byte of a 4-byte word. * * @param w * A 4-byte word. * @return w, after S-box substitution is applied to each byte. */ protected static int subWord(int w) { int subWord = 0; for (int i = 24; i >= 0; i -= 8) { int in = w << i >>> 24; subWord |= sBox[in] << (24 - i); } return subWord; } /** * Multiplies x times a polynomial b(x) in GF(2^8) modulo the irreducible * polynomial m(x) = x^8+x^4+x^3+x+1. (i.e. m(x) = 0x11b). * * @param b * A polynomial b(x) = b7x^7+b6x^6+b5x^5+b4x^4+b3x^3+b2x^2+b1x+b0 in * GF(2^8). * @return xb(x) mod x8+x4+x3+x+1. */ protected static int xtime(int b) { if ((b & 0x80) == 0) return b << 1; return (b << 1) ^ 0x11b; } /** * Test Driver. * * @param argv * @throws java.io.IOException */ public static void main(String[] argv) throws java.io.IOException { byte[] x = new byte[16]; byte[] z = new byte[16]; System.in.read(z); AES aes = new AES(z); while (System.in.read(x) != -1) System.out.write(aes.decrypt(aes.encrypt(x))); } }
