class XTS {

        /**
         * Galois field feedback.
         */
        private static final int GF_128_FEEDBACK = 0x87;

        /**
         * The AES encryption block size.
         */
        private static final int CIPHER_BLOCK_SIZE = 16;

        private final BlockCipher cipher;

        XTS(BlockCipher cipher) {
            this.cipher = cipher;
        }

        /**
         * Encrypt the data.
         *
         * @param id the (sector) id
         * @param len the number of bytes
         * @param data the data
         * @param offset the offset within the data
         */
        void encrypt(long id, int len, byte[] data, int offset) {
            byte[] tweak = initTweak(id);
            int i = 0;
            for (; i + CIPHER_BLOCK_SIZE <= len; i += CIPHER_BLOCK_SIZE) {
                if (i > 0) {
                    updateTweak(tweak);
                }
                xorTweak(data, i + offset, tweak);
                cipher.encrypt(data, i + offset, CIPHER_BLOCK_SIZE);
                xorTweak(data, i + offset, tweak);
            }
            if (i < len) {
                updateTweak(tweak);
                swap(data, i + offset, i - CIPHER_BLOCK_SIZE + offset, len - i);
                xorTweak(data, i - CIPHER_BLOCK_SIZE + offset, tweak);
                cipher.encrypt(data, i - CIPHER_BLOCK_SIZE + offset, CIPHER_BLOCK_SIZE);
                xorTweak(data, i - CIPHER_BLOCK_SIZE + offset, tweak);
            }
        }

        /**
         * Decrypt the data.
         *
         * @param id the (sector) id
         * @param len the number of bytes
         * @param data the data
         * @param offset the offset within the data
         */
        void decrypt(long id, int len, byte[] data, int offset) {
            byte[] tweak = initTweak(id), tweakEnd = tweak;
            int i = 0;
            for (; i + CIPHER_BLOCK_SIZE <= len; i += CIPHER_BLOCK_SIZE) {
                if (i > 0) {
                    updateTweak(tweak);
                    if (i + CIPHER_BLOCK_SIZE + CIPHER_BLOCK_SIZE > len && i + CIPHER_BLOCK_SIZE < len) {
                        tweakEnd = Arrays.copyOf(tweak, CIPHER_BLOCK_SIZE);
                        updateTweak(tweak);
                    }
                }
                xorTweak(data, i + offset, tweak);
                cipher.decrypt(data, i + offset, CIPHER_BLOCK_SIZE);
                xorTweak(data, i + offset, tweak);
            }
            if (i < len) {
                swap(data, i, i - CIPHER_BLOCK_SIZE + offset, len - i + offset);
                xorTweak(data, i - CIPHER_BLOCK_SIZE + offset, tweakEnd);
                cipher.decrypt(data, i - CIPHER_BLOCK_SIZE + offset, CIPHER_BLOCK_SIZE);
                xorTweak(data, i - CIPHER_BLOCK_SIZE + offset, tweakEnd);
            }
        }

        private byte[] initTweak(long id) {
            byte[] tweak = new byte[CIPHER_BLOCK_SIZE];
            for (int j = 0; j < CIPHER_BLOCK_SIZE; j++, id >>>= 8) {
                tweak[j] = (byte) (id & 0xff);
            }
            cipher.encrypt(tweak, 0, CIPHER_BLOCK_SIZE);
            return tweak;
        }

        private static void xorTweak(byte[] data, int pos, byte[] tweak) {<FILL_FUNCTION_BODY>}

        private static void updateTweak(byte[] tweak) {
            byte ci = 0, co = 0;
            for (int i = 0; i < CIPHER_BLOCK_SIZE; i++) {
                co = (byte) ((tweak[i] >> 7) & 1);
                tweak[i] = (byte) (((tweak[i] << 1) + ci) & 255);
                ci = co;
            }
            if (co != 0) {
                tweak[0] ^= GF_128_FEEDBACK;
            }
        }

        private static void swap(byte[] data, int source, int target, int len) {
            for (int i = 0; i < len; i++) {
                byte temp = data[source + i];
                data[source + i] = data[target + i];
                data[target + i] = temp;
            }
        }
    }

            for (int i = 0; i < CIPHER_BLOCK_SIZE; i++) {
                data[pos + i] ^= tweak[i];
            }
        
<methods>public non-sealed void <init>() ,public void force(boolean) throws java.io.IOException,public java.nio.channels.FileLock lock(long, long, boolean) throws java.io.IOException,public java.nio.MappedByteBuffer map(java.nio.channels.FileChannel.MapMode, long, long) throws java.io.IOException,public abstract long position() throws java.io.IOException,public abstract java.nio.channels.FileChannel position(long) throws java.io.IOException,public abstract int read(java.nio.ByteBuffer) throws java.io.IOException,public synchronized int read(java.nio.ByteBuffer, long) throws java.io.IOException,public long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException,public abstract long size() throws java.io.IOException,public long transferFrom(java.nio.channels.ReadableByteChannel, long, long) throws java.io.IOException,public long transferTo(long, long, java.nio.channels.WritableByteChannel) throws java.io.IOException,public abstract java.nio.channels.FileChannel truncate(long) throws java.io.IOException,public java.nio.channels.FileLock tryLock(long, long, boolean) throws java.io.IOException,public abstract int write(java.nio.ByteBuffer) throws java.io.IOException,public synchronized int write(java.nio.ByteBuffer, long) throws java.io.IOException,public long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException<variables>