RFR: 8298865: Excessive memory allocation in CipherOutputStream AEAD decryption [v2]

Valerie Peng valeriep at openjdk.org
Thu Dec 15 22:49:06 UTC 2022


On Thu, 15 Dec 2022 18:06:38 GMT, Daniel Jeliński <djelinski at openjdk.org> wrote:

>> This patch modifies `CipherOutputStream` to avoid pointless memory allocations when decrypting data using AEAD ciphers. This is related to #11597, which fixed a similar issue in `CipherInputStream`.
>> 
>> `Cipher.update` does not output any data when doing AEAD decryption; all data is buffered, and is later returned in one shot from `doFinal`. `Cipher.getOutputSize` returns the buffer size required by `doFinal`, which increases after every `update`, triggering new allocation in `ensureCapacity`.
>> 
>> This patch addresses the issue by calling the `update` overload that returns the output buffer until one of the update calls returns some data. When that happens, we know that the cipher does not buffer everything until `doFinal`, and revert to original behavior.
>> 
>> This PR adds a new benchmark for AES/GCM encryption and decryption using `CipherOutputStream`.
>> 
>> Benchmark results before:
>> 
>> Benchmark                         (dataSize)  (keyLength)  (provider)   Mode  Cnt       Score      Error  Units
>> AESGCMCipherOutputStream.decrypt       16384          128              thrpt   40   27949,624 ±  301,408  ops/s
>> AESGCMCipherOutputStream.decrypt     1048576          128              thrpt   40      20,730 ±    0,875  ops/s
>> AESGCMCipherOutputStream.encrypt       16384          128              thrpt   40  175358,641 ± 4235,808  ops/s
>> AESGCMCipherOutputStream.encrypt     1048576          128              thrpt   40    2588,111 ±   35,469  ops/s
>> 
>> 
>> after:
>> 
>> Benchmark                         (dataSize)  (keyLength)  (provider)   Mode  Cnt       Score      Error  Units
>> AESGCMCipherOutputStream.decrypt       16384          128              thrpt   40   69644,217 ± 1081,032  ops/s
>> AESGCMCipherOutputStream.decrypt     1048576          128              thrpt   40     949,667 ±    9,431  ops/s
>> AESGCMCipherOutputStream.encrypt       16384          128              thrpt   40  173144,038 ± 3279,149  ops/s
>> AESGCMCipherOutputStream.encrypt     1048576          128              thrpt   40    2514,840 ±   87,935  ops/s
>
> Daniel Jeliński has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Fix test failure

src/java.base/share/classes/javax/crypto/CipherOutputStream.java line 95:

> 93:      *
> 94:      * If obuffer is null/zero-sized, do not allocate a new buffer.
> 95:      * This reduces allocation for AEAD ciphers that never return data from update

AEAD ciphers do return data for update() calls for encryption. Perhaps we should add "when used for decryption" or some other similar wordings to the above sentence? Same goes for the comment in CipherInputStream class.

-------------

PR: https://git.openjdk.org/jdk/pull/11693


More information about the security-dev mailing list