This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-crypto.git
The following commit(s) were added to refs/heads/master by this push: new d669943 Reuse own API and use ternary expressions d669943 is described below commit d669943573a9ef2df1f684e32f81ffe1e09b08fd Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Sun Dec 11 12:26:32 2022 -0500 Reuse own API and use ternary expressions --- .../crypto/stream/PositionedCryptoInputStream.java | 352 ++++++++++----------- .../org/apache/commons/crypto/utils/Utils.java | 4 +- 2 files changed, 170 insertions(+), 186 deletions(-) diff --git a/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java b/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java index a0e7b04..632a552 100644 --- a/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java +++ b/src/main/java/org/apache/commons/crypto/stream/PositionedCryptoInputStream.java @@ -28,7 +28,6 @@ import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import org.apache.commons.crypto.cipher.CryptoCipher; -import org.apache.commons.crypto.cipher.CryptoCipherFactory; import org.apache.commons.crypto.stream.input.Input; import org.apache.commons.crypto.utils.AES; import org.apache.commons.crypto.utils.IoUtils; @@ -41,15 +40,58 @@ import org.apache.commons.crypto.utils.Utils; */ public class PositionedCryptoInputStream extends CtrCryptoInputStream { + private static class CipherState { + + private final CryptoCipher cryptoCipher; + private boolean reset; + + /** + * Constructs a new instance. + * + * @param cryptoCipher the CryptoCipher instance. + */ + public CipherState(final CryptoCipher cryptoCipher) { + this.cryptoCipher = cryptoCipher; + this.reset = false; + } + + /** + * Gets the CryptoCipher instance. + * + * @return the cipher. + */ + public CryptoCipher getCryptoCipher() { + return cryptoCipher; + } + + /** + * Gets the reset. + * + * @return the value of reset. + */ + public boolean isReset() { + return reset; + } + + /** + * Sets the value of reset. + * + * @param reset the reset. + */ + public void reset(final boolean reset) { + this.reset = reset; + } + } + /** * DirectBuffer pool */ - private final Queue<ByteBuffer> bufferPool = new ConcurrentLinkedQueue<>(); + private final Queue<ByteBuffer> byteBufferPool = new ConcurrentLinkedQueue<>(); /** * CryptoCipher pool */ - private final Queue<CipherState> cipherPool = new ConcurrentLinkedQueue<>(); + private final Queue<CipherState> cipherStatePool = new ConcurrentLinkedQueue<>(); /** * properties for constructing a CryptoCipher @@ -93,62 +135,60 @@ public class PositionedCryptoInputStream extends CtrCryptoInputStream { this.properties = properties; } - /** - * 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(final long position, final byte[] buffer, final int offset, final 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); + /** Cleans direct buffer pool */ + private void cleanBufferPool() { + ByteBuffer buf; + while ((buf = byteBufferPool.poll()) != null) { + CryptoInputStream.freeDirectBuffer(buf); } - return n; } /** - * 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. + * Overrides the {@link CryptoInputStream#close()}. Closes this input stream + * and releases any system resources associated with the stream. * - * @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(final long position, final byte[] buffer, final int offset, final 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); + @Override + public void close() throws IOException { + if (!isOpen()) { + return; } + + cleanBufferPool(); + super.close(); } /** - * 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. + * Does the decryption using inBuffer as input and outBuffer as output. Upon + * return, inBuffer is cleared; the decrypted data starts at + * outBuffer.position() and ends at outBuffer.limit(). * - * @param position the offset from the start of the stream. - * @param buffer the buffer into which the data is read. + * @param state the CipherState instance. + * @param inByteBuffer the input buffer. + * @param outByteBuffer the output buffer. + * @param padding the padding. * @throws IOException if an I/O error occurs. */ - public void readFully(final long position, final byte[] buffer) throws IOException { - readFully(position, buffer, 0, buffer.length); + private void decrypt(final CipherState state, final ByteBuffer inByteBuffer, + final ByteBuffer outByteBuffer, final byte padding) throws IOException { + Utils.checkState(inByteBuffer.position() >= padding); + if (inByteBuffer.position() == padding) { + // There is no real data in inBuffer. + return; + } + inByteBuffer.flip(); + outByteBuffer.clear(); + decryptBuffer(state, inByteBuffer, outByteBuffer); + inByteBuffer.clear(); + outByteBuffer.flip(); + if (padding > 0) { + /* + * The plain text and cipher text have a 1:1 mapping, they start at + * the same position. + */ + outByteBuffer.position(padding); + } } /** @@ -186,41 +226,9 @@ public class PositionedCryptoInputStream extends CtrCryptoInputStream { padding = postDecryption(state, inByteBuffer, position + n, iv); } } finally { - returnBuffer(inByteBuffer); - returnBuffer(outByteBuffer); - returnCipherState(state); - } - } - - /** - * Does the decryption using inBuffer as input and outBuffer as output. Upon - * return, inBuffer is cleared; the decrypted data starts at - * outBuffer.position() and ends at outBuffer.limit(). - * - * @param state the CipherState instance. - * @param inByteBuffer the input buffer. - * @param outByteBuffer the output buffer. - * @param padding the padding. - * @throws IOException if an I/O error occurs. - */ - private void decrypt(final CipherState state, final ByteBuffer inByteBuffer, - final ByteBuffer outByteBuffer, final byte padding) throws IOException { - Utils.checkState(inByteBuffer.position() >= padding); - if (inByteBuffer.position() == padding) { - // There is no real data in inBuffer. - return; - } - inByteBuffer.flip(); - outByteBuffer.clear(); - decryptBuffer(state, inByteBuffer, outByteBuffer); - inByteBuffer.clear(); - outByteBuffer.flip(); - if (padding > 0) { - /* - * The plain text and cipher text have a 1:1 mapping, they start at - * the same position. - */ - outByteBuffer.position(padding); + returnToPool(inByteBuffer); + returnToPool(outByteBuffer); + returnToPool(state); } } @@ -252,6 +260,28 @@ public class PositionedCryptoInputStream extends CtrCryptoInputStream { } } + /** + * Gets direct buffer from pool. Caller MUST also call {@link #returnToPool(ByteBuffer)}. + * + * @return the buffer. + * @see #returnToPool(ByteBuffer) + */ + private ByteBuffer getBuffer() { + ByteBuffer buffer = byteBufferPool.poll(); + return buffer != null ? buffer : ByteBuffer.allocateDirect(getBufferSize()); + } + + /** + * Gets CryptoCipher from pool. Caller MUST also call {@link #returnToPool(CipherState)}. + * + * @return the CipherState instance. + * @throws IOException if an I/O error occurs. + */ + private CipherState getCipherState() throws IOException { + CipherState state = cipherStatePool.poll(); + return state != null ? state : new CipherState(Utils.getCipherInstance(AES.CTR_NO_PADDING, properties)); + } + /** * This method is executed immediately after decryption. Check whether * cipher should be updated and recalculate padding if needed. @@ -280,68 +310,80 @@ public class PositionedCryptoInputStream extends CtrCryptoInputStream { } /** - * Calculates the counter and iv, reset the cipher. + * 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 state the CipherState instance. + * @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. - * @param iv the iv. + * @throws IOException if an I/O error occurs. + * @return int the total number of decrypted data bytes read into the + * buffer. */ - @SuppressWarnings("resource") // getCryptoCipher does not allocate - private void resetCipher(final CipherState state, final long position, final byte[] iv) { - final long counter = getCounter(position); - CtrCryptoInputStream.calculateIV(getInitIV(), counter, iv); - try { - state.getCryptoCipher().init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); - } catch (final GeneralSecurityException e) { - // Ignore + public int read(final long position, final byte[] buffer, final int offset, final 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); } - state.reset(false); + return n; } /** - * Gets CryptoCipher from pool. + * 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. * - * @return the CipherState instance. + * @param position the offset from the start of the stream. + * @param buffer the buffer into which the data is read. * @throws IOException if an I/O error occurs. */ - private CipherState getCipherState() throws IOException { - CipherState state = cipherPool.poll(); - if (state == null) { - final CryptoCipher cryptoCipher; - try { - cryptoCipher = CryptoCipherFactory.getCryptoCipher(AES.CTR_NO_PADDING, properties); - } catch (final GeneralSecurityException e) { - throw new IOException(e); - } - state = new CipherState(cryptoCipher); - } - - return state; + public void readFully(final long position, final byte[] buffer) throws IOException { + readFully(position, buffer, 0, buffer.length); } /** - * Returns CryptoCipher to pool. + * 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 state the CipherState instance. + * @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. */ - private void returnCipherState(final CipherState state) { - if (state != null) { - cipherPool.add(state); + public void readFully(final long position, final byte[] buffer, final int offset, final 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); } } /** - * Gets direct buffer from pool. + * Calculates the counter and iv, reset the cipher. * - * @return the buffer. + * @param state the CipherState instance. + * @param position the offset from the start of the stream. + * @param iv the iv. */ - private ByteBuffer getBuffer() { - ByteBuffer buffer = bufferPool.poll(); - if (buffer == null) { - buffer = ByteBuffer.allocateDirect(getBufferSize()); + @SuppressWarnings("resource") // getCryptoCipher does not allocate + private void resetCipher(final CipherState state, final long position, final byte[] iv) { + final long counter = getCounter(position); + CtrCryptoInputStream.calculateIV(getInitIV(), counter, iv); + try { + state.getCryptoCipher().init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + } catch (final GeneralSecurityException e) { + // Ignore } - - return buffer; + state.reset(false); } /** @@ -349,77 +391,21 @@ public class PositionedCryptoInputStream extends CtrCryptoInputStream { * * @param buf the buffer. */ - private void returnBuffer(final ByteBuffer buf) { + private void returnToPool(final ByteBuffer buf) { if (buf != null) { buf.clear(); - bufferPool.add(buf); + byteBufferPool.add(buf); } } /** - * Overrides the {@link CryptoInputStream#close()}. Closes this input stream - * and releases any system resources associated with the stream. + * Returns CryptoCipher to pool. * - * @throws IOException if an I/O error occurs. + * @param state the CipherState instance. */ - @Override - public void close() throws IOException { - if (!isOpen()) { - return; - } - - cleanBufferPool(); - super.close(); - } - - /** Cleans direct buffer pool */ - private void cleanBufferPool() { - ByteBuffer buf; - while ((buf = bufferPool.poll()) != null) { - CryptoInputStream.freeDirectBuffer(buf); - } - } - - private static class CipherState { - - private final CryptoCipher cryptoCipher; - private boolean reset; - - /** - * Constructs a new instance. - * - * @param cryptoCipher the CryptoCipher instance. - */ - public CipherState(final CryptoCipher cryptoCipher) { - this.cryptoCipher = cryptoCipher; - this.reset = false; - } - - /** - * Gets the CryptoCipher instance. - * - * @return the cipher. - */ - public CryptoCipher getCryptoCipher() { - return cryptoCipher; - } - - /** - * Gets the reset. - * - * @return the value of reset. - */ - public boolean isReset() { - return reset; - } - - /** - * Sets the value of reset. - * - * @param reset the reset. - */ - public void reset(final boolean reset) { - this.reset = reset; + private void returnToPool(final CipherState state) { + if (state != null) { + cipherStatePool.add(state); } } } diff --git a/src/main/java/org/apache/commons/crypto/utils/Utils.java b/src/main/java/org/apache/commons/crypto/utils/Utils.java index 15e7c91..c0d9ec1 100644 --- a/src/main/java/org/apache/commons/crypto/utils/Utils.java +++ b/src/main/java/org/apache/commons/crypto/utils/Utils.java @@ -120,9 +120,7 @@ public final class Utils { * @return the CryptoCipher instance. * @throws IOException if an I/O error occurs. */ - public static CryptoCipher getCipherInstance( - final String transformation, final Properties properties) - throws IOException { + public static CryptoCipher getCipherInstance(final String transformation, final Properties properties) throws IOException { try { return CryptoCipherFactory.getCryptoCipher(transformation, properties); } catch (final GeneralSecurityException e) {