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] = s[r] ^ ((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]) ^ mult(0x0b, s[1]) ^ mult(0x0d, s[2])
          ^ mult(0x09, s[3]);
      temp1 = mult(0x09, s[0]) ^ mult(0x0e, s[1]) ^ mult(0x0b, s[2])
          ^ mult(0x0d, s[3]);
      temp2 = mult(0x0d, s[0]) ^ mult(0x09, s[1]) ^ mult(0x0e, s[2])
          ^ mult(0x0b, s[3]);
      temp3 = mult(0x0b, s[0]) ^ mult(0x0d, s[1]) ^ mult(0x09, s[2])
          ^ mult(0x0e, s[3]);

      s[0] = temp0;
      s[1] = temp1;
      s[2] = temp2;
      s[3] = 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]) ^ mult(0x03, s[1]) ^ s[2] ^ s[3];
      temp1 = s[0] ^ mult(0x02, s[1]) ^ mult(0x03, s[2]) ^ s[3];
      temp2 = s[0] ^ s[1] ^ mult(0x02, s[2]) ^ mult(0x03, s[3]);
      temp3 = mult(0x03, s[0]) ^ s[1] ^ s[2] ^ mult(0x02, s[3]);

      s[0] = temp0;
      s[1] = temp1;
      s[2] = temp2;
      s[3] = 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)));

  }

}