|
17 | 17 | public class CipherSubscriber implements Subscriber<ByteBuffer> { |
18 | 18 | private final AtomicLong contentRead = new AtomicLong(0); |
19 | 19 | private final Subscriber<? super ByteBuffer> wrappedSubscriber; |
20 | | - private Cipher cipher; |
| 20 | + private final Cipher cipher; |
21 | 21 | private final Long contentLength; |
22 | | - private boolean isLastPart; |
23 | | - private int tagLength; |
24 | | - private AtomicBoolean finalBytesCalled = new AtomicBoolean(false); |
| 22 | + private final boolean isLastPart; |
| 23 | + private final int tagLength; |
| 24 | + private final AtomicBoolean finalBytesCalled = new AtomicBoolean(false); |
25 | 25 |
|
26 | 26 | private byte[] outputBuffer; |
27 | 27 |
|
28 | 28 | CipherSubscriber(Subscriber<? super ByteBuffer> wrappedSubscriber, Long contentLength, CryptographicMaterials materials, byte[] iv, boolean isLastPart) { |
29 | 29 | this.wrappedSubscriber = wrappedSubscriber; |
30 | 30 | this.contentLength = contentLength; |
31 | | - cipher = materials.getCipher(iv); |
| 31 | + this.cipher = materials.getCipher(iv); |
32 | 32 | this.isLastPart = isLastPart; |
33 | | - |
34 | | - // Determine the tag length based on the cipher algorithm. |
35 | | - // This class uses the tag length to identify the end of the stream before the onComplete signal is sent. |
36 | | - if (cipher.getAlgorithm().contains("GCM")) { |
37 | | - tagLength = 16; |
38 | | - } else if (cipher.getAlgorithm().contains("CBC") || cipher.getAlgorithm().contains("CTR")) { |
39 | | - tagLength = 0; |
40 | | - } else { |
41 | | - throw new IllegalArgumentException("Unsupported cipher type: " + cipher.getAlgorithm()); |
42 | | - } |
| 33 | + this.tagLength = materials.algorithmSuite().cipherTagLengthBytes(); |
43 | 34 | } |
44 | 35 |
|
45 | 36 | CipherSubscriber(Subscriber<? super ByteBuffer> wrappedSubscriber, Long contentLength, CryptographicMaterials materials, byte[] iv) { |
@@ -140,7 +131,12 @@ public void onComplete() { |
140 | 131 | wrappedSubscriber.onComplete(); |
141 | 132 | } |
142 | 133 |
|
143 | | - public void finalBytes() { |
| 134 | + /** |
| 135 | + * Finalize encryption, including calculating the auth tag for AES-GCM. |
| 136 | + * As such this method MUST only be called once, which is enforced using |
| 137 | + * `finalBytesCalled`. |
| 138 | + */ |
| 139 | + private void finalBytes() { |
144 | 140 | if (!finalBytesCalled.compareAndSet(false, true)) { |
145 | 141 | // already called, don't repeat |
146 | 142 | return; |
|
0 commit comments