private byte[] invertW(final byte[] wrapped) throws GeneralSecurityException {
    // Checks the input size for which invertW is defined.
    // The caller ensures stricter limits
    if (wrapped.length < 24 || wrapped.length % 8 != 0) {
      throw new GeneralSecurityException("Incorrect data size");
    }
    byte[] data = Arrays.copyOf(wrapped, wrapped.length);
    int blocks = data.length / 8 - 1;
    Cipher aes = EngineFactory.CIPHER.getInstance("AES/ECB/NoPadding");
    aes.init(Cipher.DECRYPT_MODE, aesKey);
    byte[] block = new byte[16];
    System.arraycopy(data, 0, block, 0, 8);
    for (int i = ROUNDS - 1; i >= 0; i--) {
      for (int j = blocks - 1; j >= 0; j--) {
        System.arraycopy(data, 8 * (j + 1), block, 8, 8);
        // xor the round constant in bigendian order to the left half of block. 
        int roundConst = i * blocks + j + 1;
        for (int b = 0; b < 4; b++) {
          block[7 - b] ^= (byte) (roundConst & 0xff);
          roundConst >>>= 8;
        }

        int length = aes.doFinal(block, 0, 16, block);
        assert length == 16;
        System.arraycopy(block, 8, data, 8 * (j + 1), 8);
      }
    }
    System.arraycopy(block, 0, data, 0, 8);
    return data;
  }
Compute the inverse of the pseudorandom permutation W.
@param wrapped the input data to invert. This is the wrapped key.
@return the concatenation of the IV followed by a potentially
        zero padded key.
        invertW does not perform an integrity check.
java_src/src/main/java/com/google/crypto/tink/subtle/Kwp.java