From d1c10b7598a1fd1a17107ef5c2781819a3c57c52 Mon Sep 17 00:00:00 2001 From: Tor Brede Vekterli Date: Wed, 16 Nov 2022 11:39:21 +0100 Subject: Use BouncyCastle AES GCM cipher and I/O streams instead of JCA This resolves two issues: * `javax.crypto.OutputCipherStream` swallows MAC tag mismatch exceptions when the stream is closed, which means that corruptions (intentional or not) are not caught. This is documented behavior, but still very surprising and a rather questionable default. BC's interchangeable `CipherOutputStream` throws as expected. To avoid regressions, add an explicit test that both ciphertext and MAC tag corruptions are propagated. * The default-provided `AES/GCM/NoPadding` `Cipher` instance will not emit decrypted plaintext per `update()` chunk, but buffer everything until `doFinal()` is invoked when the stream is closed. This means that decrypting very large ciphertexts can blow up memory usage since internal output buffers are reallocated and increased per iteration...! Instead use an explicit BC `GCMBlockCipher` which has the expected behavior (and actually lets cipher streams, well, _stream_). Add an `AeadCipher` abstraction to avoid leaking BC APIs outside the security module. --- .../java/com/yahoo/vespa/security/tool/crypto/CipherUtils.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'vespaclient-java/src/main/java/com/yahoo') diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/CipherUtils.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/CipherUtils.java index 051189c20b6..87d3cb4d9f0 100644 --- a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/CipherUtils.java +++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/CipherUtils.java @@ -1,8 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.security.tool.crypto; -import javax.crypto.Cipher; -import javax.crypto.CipherOutputStream; +import com.yahoo.security.AeadCipher; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -19,11 +19,11 @@ public class CipherUtils { * * @param input source stream to read from * @param output destination stream to write to - * @param cipher a Cipher in either ENCRYPT or DECRYPT mode + * @param cipher an {@link AeadCipher} created with for either encryption or decryption * @throws IOException if any file operation fails */ - public static void streamEncipher(InputStream input, OutputStream output, Cipher cipher) throws IOException { - try (var cipherStream = new CipherOutputStream(output, cipher)) { + public static void streamEncipher(InputStream input, OutputStream output, AeadCipher cipher) throws IOException { + try (var cipherStream = cipher.wrapOutputStream(output)) { input.transferTo(cipherStream); cipherStream.flush(); } -- cgit v1.2.3