security(lib): enforce single-use encryption contexts
This commit is contained in:
@@ -128,7 +128,6 @@ public class AesGcmCrossCheckTest {
|
||||
|
||||
// --- test vectors ---
|
||||
byte[] msg = rand(SIZE);
|
||||
byte[] iv = rand(12); // 12-byte IV for GCM
|
||||
byte[] aad = "test-aad-123".getBytes();
|
||||
|
||||
// --- key (either via your builder or direct JCA; both fine) ---
|
||||
@@ -139,10 +138,8 @@ public class AesGcmCrossCheckTest {
|
||||
// kg.init(256);
|
||||
// SecretKey key = kg.generateKey();
|
||||
|
||||
// --- per-test context; store IV/AAD under the names AesCipherContext expects
|
||||
// ---
|
||||
// --- per-test context; encryption generates IV and stores it here ---
|
||||
CtxInterface session = Ctx.INSTANCE.getContext("aes-gcm-xchk-" + System.nanoTime());
|
||||
session.put(ConfluxKeys.iv("AES"), iv);
|
||||
session.put(ConfluxKeys.aad("AES"), aad);
|
||||
|
||||
AesSpec spec = AesSpec.gcm128(null);
|
||||
@@ -152,6 +149,7 @@ public class AesGcmCrossCheckTest {
|
||||
((ContextAware) enc).setContext(session);
|
||||
byte[] ct_stream = readAll(enc.attach(new ByteArrayInputStream(msg)));
|
||||
enc.close();
|
||||
byte[] iv = session.get(ConfluxKeys.iv("AES"));
|
||||
|
||||
// === JCA ENCRYPT (reference) ===
|
||||
byte[] ct_jca = jcaGcmEncrypt(key, iv, TAG_BITS, aad, msg);
|
||||
|
||||
@@ -6,18 +6,28 @@ package zeroecho.core.alg.aes;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
@@ -31,6 +41,7 @@ import zeroecho.core.KeyUsage;
|
||||
import zeroecho.core.context.EncryptionContext;
|
||||
import zeroecho.core.spec.VoidSpec;
|
||||
import zeroecho.core.spi.ContextAware;
|
||||
import zeroecho.sdk.builders.alg.AesDataContentBuilder;
|
||||
import zeroecho.sdk.util.RandomSupport;
|
||||
|
||||
class AesRandomSupportTest {
|
||||
@@ -89,7 +100,113 @@ class AesRandomSupportTest {
|
||||
assertArrayEquals(repeated((byte) 1, 12), firstIv);
|
||||
assertArrayEquals(repeated((byte) 2, 12), secondIv);
|
||||
assertNotSame(firstIv, secondIv);
|
||||
System.out.println("...randomCalls=" + random.calls);
|
||||
System.out.println("...randomCalls=" + random.calls());
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
void encryptionIgnoresPreseededIvAndContextIsSingleUse() throws Exception {
|
||||
System.out.print("AesRandomSupport/encryptionIgnoresPreseededIvAndContextIsSingleUse...");
|
||||
CountingSecureRandom random = new CountingSecureRandom();
|
||||
CtxInterface session = Ctx.INSTANCE.getContext("aes-preseeded");
|
||||
session.put(ConfluxKeys.iv("AES"), repeated((byte) 9, 12));
|
||||
AesCipherContext context = new AesCipherContext(new AesAlgorithm(), KEY, true, AesSpec.gcm128(null), random);
|
||||
((ContextAware) context).setContext(session);
|
||||
|
||||
try (InputStream stream = context.attach(new ByteArrayInputStream(new byte[0]))) {
|
||||
stream.readAllBytes();
|
||||
}
|
||||
IOException failure = assertThrows(IOException.class,
|
||||
() -> context.attach(new ByteArrayInputStream(new byte[0])));
|
||||
|
||||
assertArrayEquals(repeated((byte) 1, 12), session.get(ConfluxKeys.iv("AES")));
|
||||
assertEquals(1, random.calls());
|
||||
assertEquals("AES encryption context is single-use", failure.getMessage());
|
||||
System.out.println("...randomCalls=" + random.calls());
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
void streamFailureConsumesEncryptionContext() throws Exception {
|
||||
System.out.print("AesRandomSupport/streamFailureConsumesEncryptionContext...");
|
||||
CountingSecureRandom random = new CountingSecureRandom();
|
||||
AesCipherContext context = new AesCipherContext(new AesAlgorithm(), KEY, true, AesSpec.gcm128(null), random);
|
||||
((ContextAware) context).setContext(Ctx.INSTANCE.getContext("aes-stream-failure"));
|
||||
|
||||
InputStream failing = new InputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
throw new IOException("controlled input failure");
|
||||
}
|
||||
};
|
||||
try (InputStream stream = context.attach(failing)) {
|
||||
assertThrows(IOException.class, stream::readAllBytes);
|
||||
}
|
||||
IOException reuse = assertThrows(IOException.class,
|
||||
() -> context.attach(new ByteArrayInputStream(new byte[0])));
|
||||
|
||||
assertEquals("AES encryption context is single-use", reuse.getMessage());
|
||||
assertEquals(1, random.calls());
|
||||
System.out.println("...terminalAfterFailure=true");
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
void concurrentEncryptionClaimHasExactlyOneWinner() throws Exception {
|
||||
System.out.print("AesRandomSupport/concurrentEncryptionClaimHasExactlyOneWinner...");
|
||||
CountingSecureRandom random = new CountingSecureRandom();
|
||||
AesCipherContext context = new AesCipherContext(new AesAlgorithm(), KEY, true, AesSpec.gcm128(null), random);
|
||||
((ContextAware) context).setContext(Ctx.INSTANCE.getContext("aes-concurrent-claim"));
|
||||
CountDownLatch ready = new CountDownLatch(2);
|
||||
CountDownLatch start = new CountDownLatch(1);
|
||||
ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||
try {
|
||||
Callable<Boolean> attempt = () -> {
|
||||
ready.countDown();
|
||||
start.await();
|
||||
try (InputStream stream = context.attach(new ByteArrayInputStream(new byte[0]))) {
|
||||
stream.readAllBytes();
|
||||
return true;
|
||||
} catch (IOException expected) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Future<Boolean> first = executor.submit(attempt);
|
||||
Future<Boolean> second = executor.submit(attempt);
|
||||
ready.await();
|
||||
start.countDown();
|
||||
|
||||
assertTrue(first.get() ^ second.get());
|
||||
assertEquals(1, random.calls());
|
||||
|
||||
CountingSecureRandom independentRandom = new CountingSecureRandom();
|
||||
AesCipherContext left = encryptingContext(independentRandom, "aes-independent-left");
|
||||
AesCipherContext right = encryptingContext(independentRandom, "aes-independent-right");
|
||||
Future<byte[]> leftResult = executor.submit(() -> encryptEmpty(left));
|
||||
Future<byte[]> rightResult = executor.submit(() -> encryptEmpty(right));
|
||||
leftResult.get();
|
||||
rightResult.get();
|
||||
assertEquals(2, independentRandom.calls());
|
||||
} finally {
|
||||
executor.close();
|
||||
}
|
||||
System.out.println("...winnerCount=1");
|
||||
System.out.println("...independentRandomCalls=2");
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
void publicBuilderExposesOnlyDecryptionIvConfiguration() throws Exception {
|
||||
System.out.print("AesRandomSupport/publicBuilderExposesOnlyDecryptionIvConfiguration...");
|
||||
List<String> methodNames = Arrays.stream(AesDataContentBuilder.class.getMethods()).map(Method::getName).toList();
|
||||
|
||||
assertFalse(methodNames.contains("withIv"));
|
||||
assertTrue(methodNames.contains("withDecryptionIv"));
|
||||
AesDataContentBuilder builder = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
|
||||
.withDecryptionIv(repeated((byte) 1, 12));
|
||||
IllegalStateException failure = assertThrows(IllegalStateException.class, () -> builder.build(true));
|
||||
assertEquals("A caller-supplied IV is valid only for AES decryption", failure.getMessage());
|
||||
System.out.println("...encryptionIvSetter=false");
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@@ -130,6 +247,18 @@ class AesRandomSupportTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static AesCipherContext encryptingContext(SecureRandom random, String contextName) {
|
||||
AesCipherContext context = new AesCipherContext(new AesAlgorithm(), KEY, true, AesSpec.gcm128(null), random);
|
||||
((ContextAware) context).setContext(Ctx.INSTANCE.getContext(contextName));
|
||||
return context;
|
||||
}
|
||||
|
||||
private static byte[] encryptEmpty(AesCipherContext context) throws IOException {
|
||||
try (InputStream stream = context.attach(new ByteArrayInputStream(new byte[0]))) {
|
||||
return stream.readAllBytes();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] repeated(byte value, int length) {
|
||||
byte[] result = new byte[length];
|
||||
java.util.Arrays.fill(result, value);
|
||||
@@ -138,12 +267,16 @@ class AesRandomSupportTest {
|
||||
|
||||
private static final class CountingSecureRandom extends SecureRandom {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int calls;
|
||||
private final AtomicInteger calls = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public void nextBytes(byte[] bytes) {
|
||||
calls++;
|
||||
java.util.Arrays.fill(bytes, (byte) calls);
|
||||
int current = calls.incrementAndGet();
|
||||
java.util.Arrays.fill(bytes, (byte) current);
|
||||
}
|
||||
|
||||
private int calls() {
|
||||
return calls.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2026, Leo Galambos
|
||||
* All rights reserved.
|
||||
******************************************************************************/
|
||||
package zeroecho.core.alg.chacha;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import conflux.Ctx;
|
||||
import conflux.CtxInterface;
|
||||
import zeroecho.core.ConfluxKeys;
|
||||
import zeroecho.core.io.Util;
|
||||
import zeroecho.core.spi.ContextAware;
|
||||
import zeroecho.sdk.builders.alg.ChaChaDataContentBuilder;
|
||||
|
||||
class ChaChaNonceLifecycleTest {
|
||||
private static final String ALGORITHM_ID = "CHACHA20-POLY1305";
|
||||
private static final SecretKey KEY = new SecretKeySpec(new byte[32], "ChaCha20");
|
||||
private static final ChaCha20Poly1305Spec HEADER_SPEC = ChaCha20Poly1305Spec.builder()
|
||||
.header(new ChaCha20Poly1305HeaderCodec()).build();
|
||||
private static final ChaCha20Poly1305Spec CONTEXT_SPEC = ChaCha20Poly1305Spec.builder().header(null).build();
|
||||
|
||||
@Test
|
||||
void encryptionIgnoresPreseededNonceAndContextIsSingleUse() throws Exception {
|
||||
System.out.print("ChaChaNonceLifecycle/encryptionIgnoresPreseededNonceAndContextIsSingleUse...");
|
||||
CountingSecureRandom random = new CountingSecureRandom();
|
||||
CtxInterface operation = Ctx.INSTANCE.getContext("chacha-preseeded");
|
||||
operation.put(ConfluxKeys.iv(ALGORITHM_ID), repeated((byte) 9, 12));
|
||||
ChaCha20Poly1305CipherContext context = encryptingContext(CONTEXT_SPEC, random, operation);
|
||||
|
||||
try (InputStream stream = context.attach(new ByteArrayInputStream(new byte[0]))) {
|
||||
stream.readAllBytes();
|
||||
}
|
||||
IOException failure = assertThrows(IOException.class,
|
||||
() -> context.attach(new ByteArrayInputStream(new byte[0])));
|
||||
|
||||
assertArrayEquals(repeated((byte) 1, 12), operation.get(ConfluxKeys.iv(ALGORITHM_ID)));
|
||||
assertEquals(1, random.calls());
|
||||
assertEquals("ChaCha20-Poly1305 encryption context is single-use", failure.getMessage());
|
||||
System.out.println("...randomCalls=" + random.calls());
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
void streamFailureConsumesEncryptionContext() throws Exception {
|
||||
System.out.print("ChaChaNonceLifecycle/streamFailureConsumesEncryptionContext...");
|
||||
CountingSecureRandom random = new CountingSecureRandom();
|
||||
ChaCha20Poly1305CipherContext context = encryptingContext(CONTEXT_SPEC, random,
|
||||
Ctx.INSTANCE.getContext("chacha-stream-failure"));
|
||||
InputStream failing = new InputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
throw new IOException("controlled input failure");
|
||||
}
|
||||
};
|
||||
|
||||
try (InputStream stream = context.attach(failing)) {
|
||||
assertThrows(IOException.class, stream::readAllBytes);
|
||||
}
|
||||
IOException reuse = assertThrows(IOException.class,
|
||||
() -> context.attach(new ByteArrayInputStream(new byte[0])));
|
||||
|
||||
assertEquals("ChaCha20-Poly1305 encryption context is single-use", reuse.getMessage());
|
||||
assertEquals(1, random.calls());
|
||||
System.out.println("...terminalAfterFailure=true");
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
void concurrentClaimHasOneWinnerWhileSeparateContextsProceed() throws Exception {
|
||||
System.out.print("ChaChaNonceLifecycle/concurrentClaimHasOneWinnerWhileSeparateContextsProceed...");
|
||||
CountingSecureRandom sharedRandom = new CountingSecureRandom();
|
||||
ChaCha20Poly1305CipherContext shared = encryptingContext(CONTEXT_SPEC, sharedRandom,
|
||||
Ctx.INSTANCE.getContext("chacha-concurrent-shared"));
|
||||
CountDownLatch ready = new CountDownLatch(2);
|
||||
CountDownLatch start = new CountDownLatch(1);
|
||||
ExecutorService executor = Executors.newFixedThreadPool(4);
|
||||
try {
|
||||
Callable<Boolean> attempt = () -> {
|
||||
ready.countDown();
|
||||
start.await();
|
||||
try (InputStream stream = shared.attach(new ByteArrayInputStream(new byte[0]))) {
|
||||
stream.readAllBytes();
|
||||
return true;
|
||||
} catch (IOException expected) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Future<Boolean> first = executor.submit(attempt);
|
||||
Future<Boolean> second = executor.submit(attempt);
|
||||
ready.await();
|
||||
start.countDown();
|
||||
assertTrue(first.get() ^ second.get());
|
||||
assertEquals(1, sharedRandom.calls());
|
||||
|
||||
CountingSecureRandom independentRandom = new CountingSecureRandom();
|
||||
ChaCha20Poly1305CipherContext left = encryptingContext(CONTEXT_SPEC, independentRandom,
|
||||
Ctx.INSTANCE.getContext("chacha-independent-left"));
|
||||
ChaCha20Poly1305CipherContext right = encryptingContext(CONTEXT_SPEC, independentRandom,
|
||||
Ctx.INSTANCE.getContext("chacha-independent-right"));
|
||||
Future<byte[]> leftResult = executor.submit(() -> encryptEmpty(left));
|
||||
Future<byte[]> rightResult = executor.submit(() -> encryptEmpty(right));
|
||||
leftResult.get();
|
||||
rightResult.get();
|
||||
assertEquals(2, independentRandom.calls());
|
||||
} finally {
|
||||
executor.close();
|
||||
}
|
||||
System.out.println("...sharedWinners=1");
|
||||
System.out.println("...independentRandomCalls=2");
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
void encodedNonceDrivesDecryptionAndMalformedNonceFailsClosed() throws Exception {
|
||||
System.out.print("ChaChaNonceLifecycle/encodedNonceDrivesDecryptionAndMalformedNonceFailsClosed...");
|
||||
CountingSecureRandom random = new CountingSecureRandom();
|
||||
CtxInterface encryptionOperation = Ctx.INSTANCE.getContext("chacha-header-encrypt");
|
||||
byte[] plaintext = "nonce lifecycle".getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
||||
byte[] ciphertext;
|
||||
try (InputStream stream = encryptingContext(HEADER_SPEC, random, encryptionOperation)
|
||||
.attach(new ByteArrayInputStream(plaintext))) {
|
||||
ciphertext = stream.readAllBytes();
|
||||
}
|
||||
|
||||
assertArrayEquals(repeated((byte) 1, 12), Util.read(new ByteArrayInputStream(ciphertext), 12));
|
||||
assertArrayEquals(plaintext, decryptHeader(ciphertext));
|
||||
|
||||
byte[] modified = ciphertext.clone();
|
||||
modified[1] ^= 1;
|
||||
assertThrows(IOException.class, () -> decryptHeader(modified));
|
||||
assertThrows(IOException.class, () -> decryptHeader(Arrays.copyOf(ciphertext, 11)));
|
||||
assertEquals(1, random.calls());
|
||||
System.out.println("...roundTrip=true");
|
||||
System.out.println("...malformedRejected=true");
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
@Test
|
||||
void publicBuilderExposesOnlyDecryptionNonceConfiguration() {
|
||||
System.out.print("ChaChaNonceLifecycle/publicBuilderExposesOnlyDecryptionNonceConfiguration...");
|
||||
List<String> methodNames = Arrays.stream(ChaChaDataContentBuilder.class.getMethods()).map(Method::getName)
|
||||
.toList();
|
||||
|
||||
assertFalse(methodNames.contains("withNonce"));
|
||||
assertTrue(methodNames.contains("withDecryptionNonce"));
|
||||
ChaChaDataContentBuilder builder = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
|
||||
.withDecryptionNonce(repeated((byte) 1, 12));
|
||||
IllegalStateException failure = assertThrows(IllegalStateException.class, () -> builder.build(true));
|
||||
assertEquals("A caller-supplied nonce is valid only for ChaCha decryption", failure.getMessage());
|
||||
System.out.println("...encryptionNonceSetter=false");
|
||||
System.out.println("ok");
|
||||
}
|
||||
|
||||
private static ChaCha20Poly1305CipherContext encryptingContext(ChaCha20Poly1305Spec spec, SecureRandom random,
|
||||
CtxInterface operation) {
|
||||
ChaCha20Poly1305CipherContext context = new ChaCha20Poly1305CipherContext(
|
||||
new ChaCha20Poly1305Algorithm(), KEY, true, spec, random);
|
||||
((ContextAware) context).setContext(operation);
|
||||
return context;
|
||||
}
|
||||
|
||||
private static byte[] encryptEmpty(ChaCha20Poly1305CipherContext context) throws IOException {
|
||||
try (InputStream stream = context.attach(new ByteArrayInputStream(new byte[0]))) {
|
||||
return stream.readAllBytes();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] decryptHeader(byte[] ciphertext) throws Exception {
|
||||
ChaCha20Poly1305CipherContext context = new ChaCha20Poly1305CipherContext(
|
||||
new ChaCha20Poly1305Algorithm(), KEY, false, HEADER_SPEC, null);
|
||||
((ContextAware) context).setContext(Ctx.INSTANCE.getContext("chacha-header-decrypt-" + System.nanoTime()));
|
||||
try (InputStream stream = context.attach(new ByteArrayInputStream(ciphertext))) {
|
||||
return stream.readAllBytes();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] repeated(byte value, int length) {
|
||||
byte[] result = new byte[length];
|
||||
Arrays.fill(result, value);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final class CountingSecureRandom extends SecureRandom {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final AtomicInteger calls = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public void nextBytes(byte[] bytes) {
|
||||
int current = calls.incrementAndGet();
|
||||
Arrays.fill(bytes, (byte) current);
|
||||
}
|
||||
|
||||
private int calls() {
|
||||
return calls.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class HybridDerivedTest {
|
||||
AesDataContentBuilder encAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader().modeGcm(128);
|
||||
|
||||
AesDataContentBuilder returnedEnc = HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript)
|
||||
.aad(aad).applyToAesGcm(encAes, 256, 12);
|
||||
.aad(aad).applyToAesGcm(encAes, 256);
|
||||
|
||||
System.out.println("...returnedEncSame=" + (returnedEnc == encAes));
|
||||
assertSame(encAes, returnedEnc);
|
||||
@@ -90,8 +90,8 @@ public class HybridDerivedTest {
|
||||
|
||||
AesDataContentBuilder decAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader().modeGcm(128);
|
||||
|
||||
HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript).aad(aad).applyToAesGcm(decAes, 256,
|
||||
12);
|
||||
HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript).aad(aad)
|
||||
.applyToAesGcm(decAes, 256);
|
||||
|
||||
byte[] out = runDecrypt(decAes, ciphertext);
|
||||
System.out.println("...outPrefix=" + shortHex(out, 32));
|
||||
@@ -111,8 +111,8 @@ public class HybridDerivedTest {
|
||||
|
||||
AesDataContentBuilder encAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader().modeGcm(128);
|
||||
|
||||
HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript).aad(aad).applyToAesGcm(encAes, 256,
|
||||
12);
|
||||
HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript).aad(aad)
|
||||
.applyToAesGcm(encAes, 256);
|
||||
|
||||
byte[] ciphertext = runEncrypt(encAes, msg);
|
||||
System.out.println("...ciphertextLen=" + ciphertext.length);
|
||||
@@ -121,7 +121,7 @@ public class HybridDerivedTest {
|
||||
|
||||
// ...label mismatch -> wrong key/iv/aad -> decryption must fail
|
||||
HybridDerived.from(exporter).label("app/enc/aes_WRONG").transcript(transcript).aad(aad)
|
||||
.applyToAesGcm(decAesWrong, 256, 12);
|
||||
.applyToAesGcm(decAesWrong, 256);
|
||||
|
||||
assertThrows(Exception.class, () -> runDecrypt(decAesWrong, ciphertext));
|
||||
|
||||
@@ -140,7 +140,7 @@ public class HybridDerivedTest {
|
||||
ChaChaDataContentBuilder encChaCha = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader();
|
||||
|
||||
ChaChaDataContentBuilder returnedEnc = HybridDerived.from(exporter).label("app/enc/chacha")
|
||||
.transcript(transcript).aad(aad).applyToChaChaAead(encChaCha, 256, 12);
|
||||
.transcript(transcript).aad(aad).applyToChaChaAead(encChaCha, 256);
|
||||
|
||||
System.out.println("...returnedEncSame=" + (returnedEnc == encChaCha));
|
||||
assertSame(encChaCha, returnedEnc);
|
||||
@@ -152,7 +152,7 @@ public class HybridDerivedTest {
|
||||
ChaChaDataContentBuilder decChaCha = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader();
|
||||
|
||||
HybridDerived.from(exporter).label("app/enc/chacha").transcript(transcript).aad(aad)
|
||||
.applyToChaChaAead(decChaCha, 256, 12);
|
||||
.applyToChaChaAead(decChaCha, 256);
|
||||
|
||||
byte[] out = runDecrypt(decChaCha, ciphertext);
|
||||
System.out.println("...outPrefix=" + shortHex(out, 32));
|
||||
|
||||
Reference in New Issue
Block a user