/** * Reads the specified number of bytes from a given position within a * stream. This does not change the current offset of the stream and is * thread-safe. * * @param buffer the buffer into which the data is read. * @param length the maximum number of bytes to read. * @param offset the start offset in the data. * @param position the offset from the start of the stream. * @throws IOException if an I/O error occurs. */ public void readFully(long position, byte[] buffer, int offset, int length) throws IOException { checkStream(); IoUtils.readFully(input, position, buffer, offset, length); if (length > 0) { // This operation does not change the current offset of the file decrypt(position, buffer, offset, length); } }
/** * Overrides the {@link CryptoInputStream#close()}. Closes this input stream * and releases any system resources associated with the stream. * * @throws IOException if an I/O error occurs. */ @Override public void close() throws IOException { if (!isOpen()) { return; } cleanBufferPool(); super.close(); }
ByteBuffer inByteBuffer = getBuffer(); ByteBuffer outByteBuffer = getBuffer(); CipherState state = null; try { state = getCipherState(); byte[] iv = getInitIV().clone(); resetCipher(state, position, iv); byte padding = getPadding(position); decrypt(state, inByteBuffer, outByteBuffer, padding); padding = postDecryption(state, inByteBuffer, position + n, iv); returnBuffer(inByteBuffer); returnBuffer(outByteBuffer); returnCipherState(state);
/** * This method is executed immediately after decryption. Check whether * cipher should be updated and recalculate padding if needed. * * @param state the CipherState instance. * @param inByteBuffer the input buffer. * @param position the offset from the start of the stream. * @param iv the iv. * @return the padding. * @throws IOException if an I/O error occurs. */ private byte postDecryption(CipherState state, ByteBuffer inByteBuffer, long position, byte[] iv) throws IOException { byte padding = 0; if (state.isReset()) { /* * This code is generally not executed since the cipher usually * maintains cipher context (e.g. the counter) internally. However, * some implementations can't maintain context so a re-init is * necessary after each decryption call. */ resetCipher(state, position, iv); padding = getPadding(position); inByteBuffer.position(padding); } return padding; }
/** * Calculates the counter and iv, reset the cipher. * * @param state the CipherState instance. * @param position the offset from the start of the stream. * @param iv the iv. * @throws IOException if an I/O error occurs. */ private void resetCipher(CipherState state, long position, byte[] iv) throws IOException { final long counter = getCounter(position); CtrCryptoInputStream.calculateIV(getInitIV(), counter, iv); try { state.getCryptoCipher().init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); } catch (InvalidKeyException e) { throw new IOException(e); } catch (InvalidAlgorithmParameterException e) { throw new IOException(e); } state.reset(false); }
/** * Gets direct buffer from pool. * * @return the buffer. */ private ByteBuffer getBuffer() { ByteBuffer buffer = bufferPool.poll(); if (buffer == null) { buffer = ByteBuffer.allocateDirect(getBufferSize()); } return buffer; }
decryptBuffer(state, inByteBuffer, outByteBuffer); inByteBuffer.clear(); outByteBuffer.flip();
/** * Reads up to the specified number of bytes from a given position within a * stream and return the number of bytes read. This does not change the * current offset of the stream, and is thread-safe. * * @param buffer the buffer into which the data is read. * @param length the maximum number of bytes to read. * @param offset the start offset in the data. * @param position the offset from the start of the stream. * @throws IOException if an I/O error occurs. * @return int the total number of decrypted data bytes read into the * buffer. */ public int read(long position, byte[] buffer, int offset, int length) throws IOException { checkStream(); final int n = input.read(position, buffer, offset, length); if (n > 0) { // This operation does not change the current offset of the file decrypt(position, buffer, offset, n); } return n; }