updated additional Cipher tests for MemorySegment-backed ByteBuffers

This commit is contained in:
Matthew Donovan 2025-09-10 09:52:09 -04:00
parent aa8738447d
commit e7e2dc05a2
8 changed files with 587 additions and 379 deletions

View File

@ -37,6 +37,7 @@ import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.lang.foreign.Arena;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
@ -48,7 +49,7 @@ import java.util.List;
public class AEADBufferTest implements Cloneable {
// Data type for the operation
enum dtype { BYTE, HEAP, DIRECT };
enum dtype { BYTE, HEAP, DIRECT, MEMORY_SEGMENT };
// Data map
static HashMap<String, List<Data>> datamap = new HashMap<>();
// List of enum values for order of operation
@ -60,6 +61,7 @@ public class AEADBufferTest implements Cloneable {
static final int REMAINDER = -1;
String algo;
Arena arena;
boolean same = true;
int[] sizes;
boolean incremental = false;
@ -153,6 +155,14 @@ public class AEADBufferTest implements Cloneable {
* specified, the last is a doFinal, the others are updates.
*/
AEADBufferTest(String algo, List<dtype> ops) {
this(algo, ops, null);
}
AEADBufferTest(String algo, List<dtype> ops, Arena arena) {
if (arena == null && ops.contains(dtype.MEMORY_SEGMENT)) {
throw new RuntimeException("Arena must not be null if ops contains MEMORY_SEGMENT");
}
this.arena = arena;
this.algo = algo;
this.ops = ops;
theoreticalCheck = true;
@ -433,6 +443,21 @@ public class AEADBufferTest implements Cloneable {
rlen = cipher.update(b, out);
ba.write(out.array(), outOfs, rlen);
}
case MEMORY_SEGMENT -> {
ByteBuffer b = arena.allocate(plen + outOfs).asByteBuffer();
b.position(outOfs);
b.put(pt, dataoffset + inOfs, plen);
b.flip();
b.position(outOfs);
ByteBuffer out = arena.allocate(olen).asByteBuffer();
out.position(outOfs);
rlen = cipher.update(b, out);
byte[] o = new byte[rlen];
out.flip();
out.position(outOfs);
out.get(o, 0, rlen);
ba.write(o);
}
case DIRECT -> {
ByteBuffer b = ByteBuffer.allocateDirect(plen + outOfs);
b.position(outOfs);
@ -488,6 +513,23 @@ public class AEADBufferTest implements Cloneable {
rlen = cipher.doFinal(b, out);
ba.write(out.array(), outOfs, rlen);
}
case MEMORY_SEGMENT -> {
ByteBuffer b = arena.allocate(plen+inOfs).asByteBuffer();
b.limit(b.capacity());
b.position(inOfs);
b.put(pt, dataoffset + inOfs, plen);
b.flip();
b.position(inOfs);
ByteBuffer out = arena.allocate(olen).asByteBuffer();
out.limit(out.capacity());
out.position(outOfs);
rlen = cipher.doFinal(b, out);
byte[] o = new byte[rlen];
out.flip();
out.position(outOfs);
out.get(o, 0, rlen);
ba.write(o);
}
case DIRECT -> {
ByteBuffer b = ByteBuffer.allocateDirect(plen + inOfs);
b.limit(b.capacity());
@ -577,6 +619,12 @@ public class AEADBufferTest implements Cloneable {
bbin.put(data, 0, input.length + inOfs);
bbin.flip();
}
case MEMORY_SEGMENT -> {
bbin = arena.allocate(data.length).asByteBuffer();
bbout = bbin.duplicate();
bbin.put(data, 0, input.length + inOfs);
bbin.flip();
}
}
// Set data limits for bytebuffers
@ -594,7 +642,7 @@ public class AEADBufferTest implements Cloneable {
rlen = cipher.update(data, dataoffset + inOfs, plen,
data, len + outOfs);
}
case HEAP, DIRECT -> {
case HEAP, DIRECT, MEMORY_SEGMENT -> {
theorticallen = bbin.remaining() - (d.blockSize > 0 ?
bbin.remaining() % d.blockSize : 0);
rlen = cipher.update(bbin, bbout);
@ -623,7 +671,7 @@ public class AEADBufferTest implements Cloneable {
plen, data, len + outOfs);
out = Arrays.copyOfRange(data, 0,len + rlen + outOfs);
}
case HEAP, DIRECT -> {
case HEAP, DIRECT, MEMORY_SEGMENT -> {
rlen = cipher.doFinal(bbin, bbout);
bbout.flip();
out = new byte[bbout.remaining()];
@ -660,193 +708,252 @@ public class AEADBufferTest implements Cloneable {
initTest();
// **** GCM Tests
try(Arena arena = Arena.ofConfined()) {
// **** GCM Tests
// Test single byte array
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE)));
// Test update-doFinal with byte arrays
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE)));
// Test update-update-doFinal with byte arrays
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)));
// Test single byte array
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE)));
// Test update-doFinal with byte arrays
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE)));
// Test update-update-doFinal with byte arrays
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)));
// Test single heap bytebuffer
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP)));
// Test update-doFinal with heap bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.HEAP, dtype.HEAP)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP, dtype.HEAP)));
// Test update-update-doFinal with heap bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)));
// Test single heap bytebuffer
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP)));
// Test update-doFinal with heap bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.HEAP, dtype.HEAP)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP, dtype.HEAP)));
// Test update-update-doFinal with heap bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)));
// Test single direct bytebuffer
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.DIRECT)));
// Test update-doFinal with direct bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT)));
// Test update-update-doFinal with direct bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)));
// Test single direct bytebuffer
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.DIRECT)));
// Test update-doFinal with direct bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT)));
// Test update-update-doFinal with direct bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)));
// Test update-update-doFinal with byte arrays and preset data sizes
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).dataSegments(
new int[] { 1, 1, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test single memory segment bytebuffer
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.MEMORY_SEGMENT), arena).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.MEMORY_SEGMENT), arena));
// Test update-doFinal with direct bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT), arena).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT), arena));
// Test update-update-doFinal with direct bytebuffer
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT), arena).test();
offsetTests(new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT), arena));
// Test update-doFinal with a byte array and a direct bytebuffer
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.DIRECT)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a byte array and heap and direct bytebuffer
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.HEAP, dtype.DIRECT)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with byte arrays and preset data sizes
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).dataSegments(
new int[]{1, 1, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a direct bytebuffer and a byte array.
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a byte array and a direct bytebuffer
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.DIRECT)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a byte array and heap and direct bytebuffer
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.HEAP, dtype.DIRECT)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a byte array and heap and direct and memory segment bytebuffer
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.HEAP, dtype.DIRECT, dtype.MEMORY_SEGMENT), arena).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a direct bytebuffer and a byte array with
// preset data sizes.
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly().
dataSegments(new int[] { 20, AEADBufferTest.REMAINDER });
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with a direct and heap bytebuffer and a
// byte array with preset data sizes.
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.BYTE, dtype.HEAP)).
differentBufferOnly().dataSet(5).
dataSegments(new int[] { 5000, 1000, AEADBufferTest.REMAINDER });
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a direct bytebuffer and a byte array.
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with byte arrays, incrementing through
// every data size combination for the Data set 0
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).incrementalSegments().
dataSet(0).test();
// Test update-update-doFinal with direct bytebuffers, incrementing through
// every data size combination for the Data set 0
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
incrementalSegments().dataSet(0).test();
// Test update-doFinal with a direct bytebuffer and a byte array with
// preset data sizes.
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly().
dataSegments(new int[]{20, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with a direct and heap bytebuffer and a
// byte array with preset data sizes.
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.BYTE, dtype.HEAP)).
differentBufferOnly().dataSet(5).
dataSegments(new int[]{5000, 1000, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with a direct and heap and memory segment
// bytebuffer and a byte array with preset data sizes.
t = new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.BYTE, dtype.HEAP, dtype.MEMORY_SEGMENT), arena).
differentBufferOnly().dataSet(5).
dataSegments(new int[]{5000, 1000, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
dataSegments(new int[] { 49, 0, 2 }).dataSet(0).test();
// Test update-update-doFinal with byte arrays, incrementing through
// every data size combination for the Data set 0
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).incrementalSegments().
dataSet(0).test();
// Test update-update-doFinal with direct bytebuffers, incrementing through
// every data size combination for the Data set 0
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
incrementalSegments().dataSet(0).test();
// **** CC20P1305 Tests
new AEADBufferTest("AES/GCM/NoPadding",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
dataSegments(new int[]{49, 0, 2}).dataSet(0).test();
// Test single byte array
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE)));
// Test update-doFinal with byte arrays
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE, dtype.BYTE)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE, dtype.BYTE)));
// Test update-update-doFinal with byte arrays
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)));
// **** CC20P1305 Tests
// Test single heap bytebuffer
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.HEAP)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.HEAP)));
// Test update-doFinal with heap bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.HEAP, dtype.HEAP)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.HEAP, dtype.HEAP)));
// Test update-update-doFinal with heap bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)));
// Test single byte array
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE)));
// Test update-doFinal with byte arrays
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE, dtype.BYTE)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE, dtype.BYTE)));
// Test update-update-doFinal with byte arrays
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)));
// Test single direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.DIRECT)));
// Test update-doFinal with direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT)));
// Test update-update-doFinal with direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)));
// Test single heap bytebuffer
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.HEAP)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.HEAP)));
// Test update-doFinal with heap bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.HEAP, dtype.HEAP)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.HEAP, dtype.HEAP)));
// Test update-update-doFinal with heap bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)));
// Test update-update-doFinal with byte arrays and preset data sizes
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).dataSegments(
new int[] { 1, 1, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test single direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.DIRECT)));
// Test update-doFinal with direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT)));
// Test update-update-doFinal with direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)));
// Test update-doFinal with a byte array and a direct bytebuffer
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.DIRECT)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a byte array and heap and direct bytebuffer
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.HEAP, dtype.DIRECT)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test single direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.MEMORY_SEGMENT), arena).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305", List.of(dtype.MEMORY_SEGMENT), arena));
// Test update-doFinal with direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT), arena).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT), arena));
// Test update-update-doFinal with direct bytebuffer
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT), arena).test();
offsetTests(new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT, dtype.MEMORY_SEGMENT), arena));
// Test update-doFinal with a direct bytebuffer and a byte array.
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with byte arrays and preset data sizes
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).dataSegments(
new int[]{1, 1, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a direct bytebuffer and a byte array with
// preset data sizes.
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly().
dataSegments(new int[] { 20, AEADBufferTest.REMAINDER });
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with a direct and heap bytebuffer and a
// byte array with preset data sizes.
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.BYTE, dtype.HEAP)).
differentBufferOnly().dataSet(1).
dataSegments(new int[] { 5000, 1000, AEADBufferTest.REMAINDER });
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a byte array and a direct bytebuffer
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.DIRECT)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a byte array and heap and direct bytebuffer
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.HEAP, dtype.DIRECT)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with byte arrays, incrementing through
// every data size combination for the Data set 0
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).incrementalSegments().
dataSet(0).test();
// Test update-update-doFinal with direct bytebuffers, incrementing through
// every data size combination for the Data set 0
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
incrementalSegments().dataSet(0).test();
// Test update-doFinal with a byte array and heap and direct and memory segment bytebuffer
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.HEAP, dtype.DIRECT, dtype.MEMORY_SEGMENT), arena).
differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
dataSegments(new int[] { 49, 0, 2 }).dataSet(0).test();
// Test update-doFinal with a direct bytebuffer and a byte array.
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly();
t.clone().test();
offsetTests(t.clone());
// Test update-doFinal with a direct bytebuffer and a byte array with
// preset data sizes.
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly().
dataSegments(new int[]{20, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with a direct and heap bytebuffer and a
// byte array with preset data sizes.
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.BYTE, dtype.HEAP)).
differentBufferOnly().dataSet(1).
dataSegments(new int[]{5000, 1000, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with a direct and heap and memory segment
// bytebuffer and a byte array with preset data sizes.
t = new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.BYTE, dtype.HEAP, dtype.MEMORY_SEGMENT), arena).
differentBufferOnly().dataSet(1).
dataSegments(new int[]{5000, 1000, AEADBufferTest.REMAINDER});
t.clone().test();
offsetTests(t.clone());
// Test update-update-doFinal with byte arrays, incrementing through
// every data size combination for the Data set 0
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).incrementalSegments().
dataSet(0).test();
// Test update-update-doFinal with direct bytebuffers, incrementing through
// every data size combination for the Data set 0
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
incrementalSegments().dataSet(0).test();
new AEADBufferTest("ChaCha20-Poly1305",
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
dataSegments(new int[]{49, 0, 2}).dataSet(0).test();
}
}
// Test data

View File

@ -25,6 +25,7 @@ import javax.crypto.Cipher;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.lang.foreign.Arena;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HexFormat;
@ -117,6 +118,10 @@ public class GCMShortBuffer {
new GCMShortBuffer(new byte[50]);
new GCMShortBuffer(ByteBuffer.allocate(13));
new GCMShortBuffer(ByteBuffer.allocate(50));
try(Arena arena = Arena.ofConfined()) {
new GCMShortBuffer(arena.allocate(13).asByteBuffer());
new GCMShortBuffer(arena.allocate(50).asByteBuffer());
}
}

View File

@ -27,6 +27,7 @@
* @summary ArithmeticException in GaloisCounterMode
*/
import java.lang.foreign.Arena;
import java.nio.ByteBuffer;
import javax.crypto.AEADBadTagException;
@ -50,6 +51,9 @@ public class GCMShortInput {
cipher.init(Cipher.DECRYPT_MODE, keySpec, params);
try {
cipher.doFinal(ByteBuffer.allocate(0), ByteBuffer.allocate(0));
try (Arena arena = Arena.ofConfined()) {
cipher.doFinal(arena.allocate(0).asByteBuffer(), arena.allocate(0).asByteBuffer());
}
throw new AssertionError("AEADBadTagException expected");
} catch (AEADBadTagException e) {
// expected

View File

@ -25,6 +25,7 @@ import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.lang.foreign.Arena;
import java.nio.ByteBuffer;
import java.security.spec.AlgorithmParameterSpec;
@ -77,97 +78,115 @@ public class OverlapByteBuffer {
void test() throws Exception {
// Output offset from the baseBuf
for (int i = 0; i < 3; i++) {
for (outOfs = -1; outOfs <= 1; outOfs++) {
try(Arena arena = Arena.ofConfined()) {
for (int i = 0; i < 4; i++) {
for (outOfs = -1; outOfs <= 1; outOfs++) {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key, params);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key, params);
// Offset on the particular ByteBuffer (aka position())
int inOfsInBuf = 1;
int outOfsInBuf = inOfsInBuf + outOfs;
int sliceLen = cipher.getOutputSize(baseBuf.length);
int bufferSize = sliceLen + Math.max(inOfsInBuf, outOfsInBuf);
byte[] buffer;
// Create overlapping input and output buffers
switch (i) {
case 0 -> {
buffer = new byte[bufferSize];
output = ByteBuffer.wrap(buffer, outOfsInBuf, sliceLen).
slice();
input = ByteBuffer.wrap(buffer, inOfsInBuf, sliceLen).
slice();
System.out.println("Using array-backed ByteBuffer");
in = input.duplicate();
// Offset on the particular ByteBuffer (aka position())
int inOfsInBuf = 1;
int outOfsInBuf = inOfsInBuf + outOfs;
int sliceLen = cipher.getOutputSize(baseBuf.length);
int bufferSize = sliceLen + Math.max(inOfsInBuf, outOfsInBuf);
byte[] buffer;
// Create overlapping input and output buffers
switch (i) {
case 0 -> {
buffer = new byte[bufferSize];
output = ByteBuffer.wrap(buffer, outOfsInBuf, sliceLen).
slice();
input = ByteBuffer.wrap(buffer, inOfsInBuf, sliceLen).
slice();
System.out.println("Using array-backed ByteBuffer");
in = input.duplicate();
}
case 1 -> {
buffer = new byte[bufferSize];
output = ByteBuffer.wrap(buffer, outOfsInBuf, sliceLen).
slice();
input = ByteBuffer.wrap(buffer, inOfsInBuf, sliceLen).
slice();
System.out.println("Using read-only array-backed " +
"ByteBuffer");
in = input.asReadOnlyBuffer();
}
case 2 -> {
System.out.println("Using direct ByteBuffer");
ByteBuffer buf = ByteBuffer.allocateDirect(bufferSize);
output = buf.duplicate();
output.position(outOfsInBuf);
output.limit(sliceLen + outOfsInBuf);
output = output.slice();
input = buf.duplicate();
input.position(inOfsInBuf);
input.limit(sliceLen + inOfsInBuf);
input = input.slice();
in = input.duplicate();
}
case 3 -> {
System.out.println("Using memory-segment ByteBuffer");
ByteBuffer buf = arena.allocate(bufferSize).asByteBuffer();
output = buf.duplicate();
output.position(outOfsInBuf);
output.limit(sliceLen + outOfsInBuf);
output = output.slice();
input = buf.duplicate();
input.position(inOfsInBuf);
input.limit(sliceLen + inOfsInBuf);
input = input.slice();
in = input.duplicate();
}
default -> throw new Exception("Unknown index " + i);
}
case 1 -> {
buffer = new byte[bufferSize];
output = ByteBuffer.wrap(buffer, outOfsInBuf, sliceLen).
slice();
input = ByteBuffer.wrap(buffer, inOfsInBuf, sliceLen).
slice();
System.out.println("Using read-only array-backed " +
"ByteBuffer");
in = input.asReadOnlyBuffer();
}
case 2 -> {
System.out.println("Using direct ByteBuffer");
ByteBuffer buf = ByteBuffer.allocateDirect(bufferSize);
output = buf.duplicate();
output.position(outOfsInBuf);
output.limit(sliceLen + outOfsInBuf);
output = output.slice();
System.out.println("inOfsInBuf = " + inOfsInBuf);
System.out.println("outOfsInBuf = " + outOfsInBuf);
input = buf.duplicate();
input.position(inOfsInBuf);
input.limit(sliceLen + inOfsInBuf);
input = input.slice();
in = input.duplicate();
}
default -> throw new Exception("Unknown index " + i);
}
System.out.println("inOfsInBuf = " + inOfsInBuf);
System.out.println("outOfsInBuf = " + outOfsInBuf);
// Copy data into shared buffer
input.put(baseBuf);
input.flip();
in.limit(input.limit());
try {
int ctSize = cipher.doFinal(in, output);
// Get ready to decrypt
byte[] tmp = new byte[ctSize];
output.flip();
output.get(tmp);
output.clear();
input.clear();
input.put(tmp);
// Copy data into shared buffer
input.put(baseBuf);
input.flip();
in.clear();
in.limit(input.limit());
cipher.init(Cipher.DECRYPT_MODE, key, params);
cipher.doFinal(in, output);
try {
int ctSize = cipher.doFinal(in, output);
output.flip();
ByteBuffer b = ByteBuffer.wrap(baseBuf);
if (b.compareTo(output) != 0) {
System.err.println(
"\nresult (" + output + "):\n" +
byteToHex(output) +
"\nexpected (" + b + "):\n" +
byteToHex(b));
throw new Exception("Mismatch");
// Get ready to decrypt
byte[] tmp = new byte[ctSize];
output.flip();
output.get(tmp);
output.clear();
input.clear();
input.put(tmp);
input.flip();
in.clear();
in.limit(input.limit());
cipher.init(Cipher.DECRYPT_MODE, key, params);
cipher.doFinal(in, output);
output.flip();
ByteBuffer b = ByteBuffer.wrap(baseBuf);
if (b.compareTo(output) != 0) {
System.err.println(
"\nresult (" + output + "):\n" +
byteToHex(output) +
"\nexpected (" + b + "):\n" +
byteToHex(b));
throw new Exception("Mismatch");
}
} catch (Exception e) {
throw new Exception("Error with base offset " + outOfs, e);
}
} catch (Exception e) {
throw new Exception("Error with base offset " + outOfs, e);
}
}
}

View File

@ -21,6 +21,7 @@
* questions.
*/
import java.lang.foreign.Arena;
import java.nio.ByteBuffer;
import java.security.AlgorithmParameters;
import java.security.Provider;
@ -217,17 +218,27 @@ public class SameBuffer {
// prepare byte buffer contained AAD and plain text
int bufSize = AADLength + offset + outputLength;
byte[] AAD_and_Text = Helper.generateBytes(bufSize);
ByteBuffer AAD_and_Text_Buf = ByteBuffer.allocate(bufSize);
AAD_and_Text_Buf.put(AAD_and_Text, 0, AAD_and_Text.length);
// do test
runGCMWithSameBuffer(Cipher.ENCRYPT_MODE, AAD_and_Text_Buf, offset,
textLength, params);
int tagLength = c.getParameters()
.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;
AAD_and_Text_Buf.limit(AADLength + offset + textLength + tagLength);
runGCMWithSameBuffer(Cipher.DECRYPT_MODE, AAD_and_Text_Buf, offset,
textLength + tagLength, params);
try (Arena arena = Arena.ofConfined()) {
for (int i = 0; i < 2; ++i) {
ByteBuffer AAD_and_Text_Buf = switch (i) {
case 0 -> ByteBuffer.allocate(bufSize);
case 1 -> arena.allocate(bufSize).asByteBuffer();
default -> throw new RuntimeException("Unknown test case");
};
AAD_and_Text_Buf.put(AAD_and_Text, 0, AAD_and_Text.length);
// do test
runGCMWithSameBuffer(Cipher.ENCRYPT_MODE, AAD_and_Text_Buf, offset,
textLength, params);
int tagLength = c.getParameters()
.getParameterSpec(GCMParameterSpec.class).getTLen() / 8;
AAD_and_Text_Buf.limit(AADLength + offset + textLength + tagLength);
runGCMWithSameBuffer(Cipher.DECRYPT_MODE, AAD_and_Text_Buf, offset,
textLength + tagLength, params);
}
}
}

View File

@ -33,6 +33,7 @@
*/
import java.lang.foreign.Arena;
import java.nio.ByteBuffer;
import java.security.*;
import javax.crypto.*;
@ -43,6 +44,8 @@ import java.util.*;
public class TestKATForGCM {
enum BufferType { DIRECT, HEAP, MEMORY_SEGMENT };
// Utility methods
private static byte[] HexToBytes(String hexVal) {
if (hexVal == null) return new byte[0];
@ -320,7 +323,7 @@ public class TestKATForGCM {
}
}
void executeByteBuffer(TestVector tv, boolean direct, int offset) throws Exception {
void executeByteBuffer(TestVector tv, BufferType bufferType, int offset) throws Exception {
Cipher c = Cipher.getInstance("AES/GCM/NoPadding",
System.getProperty("test.provider.name", "SunJCE"));
@ -328,76 +331,92 @@ public class TestKATForGCM {
ByteBuffer ctdst;
ByteBuffer ptdst;
if (direct) {
System.out.print("Test #" + tv.id + ": ByteBuffer Direct.");
src = ByteBuffer.allocateDirect(tv.plainText.length + offset);
ctdst = ByteBuffer.allocateDirect(tv.cipherText.length + tv.tag.length + offset);
ptdst = ByteBuffer.allocateDirect(tv.plainText.length + offset);
} else {
System.out.print("Test #" + tv.id + ": ByteBuffer Heap.");
src = ByteBuffer.allocate(tv.plainText.length + offset);
ctdst = ByteBuffer.allocate(tv.cipherText.length + tv.tag.length + offset);
ptdst = ByteBuffer.allocate(tv.plainText.length + offset);
}
byte[] plainText;
if (offset > 0) {
System.out.println(" offset = " + offset);
plainText = new byte[tv.plainText.length + offset];
System.arraycopy(tv.plainText, 0, plainText, offset,
tv.plainText.length);
} else {
System.out.println();
plainText = tv.plainText;
}
src.put(plainText);
src.position(offset);
ctdst.position(offset);
ctdst.mark();
ptdst.position(offset);
ptdst.mark();
try {
c.init(Cipher.ENCRYPT_MODE, tv.key, tv.spec);
c.updateAAD(tv.aad);
c.doFinal(src, ctdst);
ctdst.reset();
ByteBuffer tag = ctdst.duplicate();
tag.position(tag.limit() - tv.tag.length);
c.init(Cipher.DECRYPT_MODE, tv.key, tv.spec);
c.updateAAD(tv.aad);
c.doFinal(ctdst, ptdst); // should fail if tag mismatched
ptdst.reset();
// check encryption/decryption results just to be sure
if (ptdst.compareTo(ByteBuffer.wrap(tv.plainText)) != 0) {
System.out.println("\t PlainText diff failed for test# " + tv.id);
testFailed = true;
try (Arena arena = Arena.ofConfined()) {
switch (bufferType) {
case DIRECT: {
System.out.print("Test #" + tv.id + ": ByteBuffer Direct.");
src = ByteBuffer.allocateDirect(tv.plainText.length + offset);
ctdst = ByteBuffer.allocateDirect(tv.cipherText.length + tv.tag.length + offset);
ptdst = ByteBuffer.allocateDirect(tv.plainText.length + offset);
}
break;
case HEAP: {
System.out.print("Test #" + tv.id + ": ByteBuffer Heap.");
src = ByteBuffer.allocate(tv.plainText.length + offset);
ctdst = ByteBuffer.allocate(tv.cipherText.length + tv.tag.length + offset);
ptdst = ByteBuffer.allocate(tv.plainText.length + offset);
}
break;
case MEMORY_SEGMENT: {
System.out.print("Test #" + tv.id + ": ByteBuffer MemorySegment.");
src = arena.allocate(tv.plainText.length + offset).asByteBuffer();
ctdst = arena.allocate(tv.cipherText.length + tv.tag.length + offset).asByteBuffer();
ptdst = arena.allocate(tv.plainText.length + offset).asByteBuffer();
}
break;
default:
throw new RuntimeException("Unsupported buffer type " + bufferType);
}
ctdst.reset();
ctdst.limit(ctdst.limit() - tv.tag.length);
if (ctdst.compareTo(ByteBuffer.wrap(tv.cipherText)) != 0) {
System.out.println("\t CipherText diff failed for test# " + tv.id);
testFailed = true;
byte[] plainText;
if (offset > 0) {
System.out.println(" offset = " + offset);
plainText = new byte[tv.plainText.length + offset];
System.arraycopy(tv.plainText, 0, plainText, offset,
tv.plainText.length);
} else {
System.out.println();
plainText = tv.plainText;
}
int mismatch = 0;
for (int i = 0; i < tv.tag.length; i++) {
mismatch |= tag.get() ^ tv.tag[i];
src.put(plainText);
src.position(offset);
ctdst.position(offset);
ctdst.mark();
ptdst.position(offset);
ptdst.mark();
try {
c.init(Cipher.ENCRYPT_MODE, tv.key, tv.spec);
c.updateAAD(tv.aad);
c.doFinal(src, ctdst);
ctdst.reset();
ByteBuffer tag = ctdst.duplicate();
tag.position(tag.limit() - tv.tag.length);
c.init(Cipher.DECRYPT_MODE, tv.key, tv.spec);
c.updateAAD(tv.aad);
c.doFinal(ctdst, ptdst); // should fail if tag mismatched
ptdst.reset();
// check encryption/decryption results just to be sure
if (ptdst.compareTo(ByteBuffer.wrap(tv.plainText)) != 0) {
System.out.println("\t PlainText diff failed for test# " + tv.id);
testFailed = true;
}
ctdst.reset();
ctdst.limit(ctdst.limit() - tv.tag.length);
if (ctdst.compareTo(ByteBuffer.wrap(tv.cipherText)) != 0) {
System.out.println("\t CipherText diff failed for test# " + tv.id);
testFailed = true;
}
int mismatch = 0;
for (int i = 0; i < tv.tag.length; i++) {
mismatch |= tag.get() ^ tv.tag[i];
}
if (mismatch != 0) {
System.out.println("\t Tag diff failed for test# " + tv.id);
testFailed = true;
}
} catch (Exception ex) {
// continue testing other test vectors
System.out.println("\t Failed Test Vector ( #" + tv.id + ") : " + tv);
ex.printStackTrace();
}
if (mismatch != 0) {
System.out.println("\t Tag diff failed for test# " + tv.id);
testFailed = true;
}
} catch (Exception ex) {
// continue testing other test vectors
System.out.println("\t Failed Test Vector ( #" + tv.id + ") : " + tv);
ex.printStackTrace();
}
}
@ -405,10 +424,12 @@ public class TestKATForGCM {
TestKATForGCM test = new TestKATForGCM();
for (TestVector tv : testValues) {
test.executeArray(tv);
test.executeByteBuffer(tv, false, 0);
test.executeByteBuffer(tv, true, 0);
test.executeByteBuffer(tv, false, 2);
test.executeByteBuffer(tv, true, 2);
test.executeByteBuffer(tv, BufferType.HEAP, 0);
test.executeByteBuffer(tv, BufferType.DIRECT, 0);
test.executeByteBuffer(tv, BufferType.MEMORY_SEGMENT, 0);
test.executeByteBuffer(tv, BufferType.HEAP, 2);
test.executeByteBuffer(tv, BufferType.DIRECT, 2);
test.executeByteBuffer(tv, BufferType.MEMORY_SEGMENT, 2);
}
if (!testFailed) {
System.out.println("Tests passed");

View File

@ -30,6 +30,7 @@
* @summary ChaCha20 Cipher Implementation (KAT)
*/
import java.lang.foreign.Arena;
import java.util.*;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
@ -200,7 +201,13 @@ public class ChaCha20KAT {
for (TestData test : testList) {
System.out.println("*** Test " + ++testNumber + ": " +
test.testName);
if (runByteBuffer(test)) {
if (runByteBuffer(test, true)) {
testsPassed++;
}
System.out.println("*** Test " + ++testNumber + ": " +
test.testName);
if (runByteBuffer(test, false)) {
testsPassed++;
}
}
@ -360,7 +367,7 @@ public class ChaCha20KAT {
System.out.println();
}
private static boolean runByteBuffer(TestData testData)
private static boolean runByteBuffer(TestData testData, boolean heap)
throws GeneralSecurityException {
boolean encRes = false;
boolean decRes = false;
@ -372,48 +379,63 @@ public class ChaCha20KAT {
testData.nonce, testData.counter);
mambo.init(Cipher.ENCRYPT_MODE, mamboKey, mamboSpec);
ByteBuffer bbIn = ByteBuffer.wrap(testData.input);
ByteBuffer bbEncOut = ByteBuffer.allocate(
mambo.getOutputSize(testData.input.length));
ByteBuffer bbExpOut = ByteBuffer.wrap(testData.expOutput);
try (Arena arena = Arena.ofConfined()) {
ByteBuffer bbIn = ByteBuffer.wrap(testData.input);
ByteBuffer bbEncOut;
ByteBuffer bbExpOut = ByteBuffer.wrap(testData.expOutput);
if (heap) {
bbEncOut = ByteBuffer.allocate(
mambo.getOutputSize(testData.input.length));
} else {
bbEncOut = arena.allocate(
mambo.getOutputSize(testData.input.length))
.asByteBuffer();
}
mambo.doFinal(bbIn, bbEncOut);
bbIn.rewind();
bbEncOut.rewind();
mambo.doFinal(bbIn, bbEncOut);
bbIn.rewind();
bbEncOut.rewind();
if (bbEncOut.compareTo(bbExpOut) != 0) {
System.out.println("ERROR - Output Mismatch!");
System.out.println("Expected:\n" +
dumpHexBytes(bbExpOut, 16, "\n", " "));
System.out.println("Actual:\n" +
dumpHexBytes(bbEncOut, 16, "\n", " "));
System.out.println();
} else {
encRes = true;
if (bbEncOut.compareTo(bbExpOut) != 0) {
System.out.println("ERROR - Output Mismatch!");
System.out.println("Expected:\n" +
dumpHexBytes(bbExpOut, 16, "\n", " "));
System.out.println("Actual:\n" +
dumpHexBytes(bbEncOut, 16, "\n", " "));
System.out.println();
} else {
encRes = true;
}
// Decrypt the result of the encryption operation
mambo = Cipher.getInstance("ChaCha20");
mambo.init(Cipher.DECRYPT_MODE, mamboKey, mamboSpec);
System.out.print("Decrypt - ");
ByteBuffer bbDecOut;
if (heap) {
bbDecOut = ByteBuffer.allocate(
mambo.getOutputSize(bbEncOut.remaining()));
} else {
bbDecOut = arena.allocate(
mambo.getOutputSize(bbEncOut.remaining()))
.asByteBuffer();
}
mambo.doFinal(bbEncOut, bbDecOut);
bbEncOut.rewind();
bbDecOut.rewind();
if (bbDecOut.compareTo(bbIn) != 0) {
System.out.println("ERROR - Output Mismatch!");
System.out.println("Expected:\n" +
dumpHexBytes(bbIn, 16, "\n", " "));
System.out.println("Actual:\n" +
dumpHexBytes(bbDecOut, 16, "\n", " "));
System.out.println();
} else {
decRes = true;
}
}
// Decrypt the result of the encryption operation
mambo = Cipher.getInstance("ChaCha20");
mambo.init(Cipher.DECRYPT_MODE, mamboKey, mamboSpec);
System.out.print("Decrypt - ");
ByteBuffer bbDecOut = ByteBuffer.allocate(
mambo.getOutputSize(bbEncOut.remaining()));
mambo.doFinal(bbEncOut, bbDecOut);
bbEncOut.rewind();
bbDecOut.rewind();
if (bbDecOut.compareTo(bbIn) != 0) {
System.out.println("ERROR - Output Mismatch!");
System.out.println("Expected:\n" +
dumpHexBytes(bbIn, 16, "\n", " "));
System.out.println("Actual:\n" +
dumpHexBytes(bbDecOut, 16, "\n", " "));
System.out.println();
} else {
decRes = true;
}
return (encRes && decRes);
}

View File

@ -21,12 +21,14 @@
* questions.
*/
import java.lang.foreign.Arena;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;
import java.util.function.Function;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
@ -119,17 +121,33 @@ public class PBMacBuffer {
theMac.init(key);
// Do large ByteBuffer test case
if (!largeByteBufferTest(theMac)) {
if (!largeByteBufferTest(theMac, this::generateRandomByteBuffer)) {
System.out.println("Large ByteBuffer test case failed.");
return false;
}
// Do empty ByteBuffer test case
if (!emptyByteBufferTest(theMac)) {
if (!emptyByteBufferTest(theMac, this::generateRandomByteBuffer)) {
System.out.println("Empty ByteBuffer test case failed.");
return false;
}
try(Arena arena = Arena.ofConfined()) {
// Do large ByteBuffer test case
if (!largeByteBufferTest(theMac,
(size) -> arena.allocate(size).asByteBuffer())) {
System.out.println("Large MemorySegment ByteBuffer test case failed.");
return false;
}
// Do empty ByteBuffer test case
if (!emptyByteBufferTest(theMac,
(size) -> arena.allocate(size).asByteBuffer())) {
System.out.println("Empty MemorySegment ByteBuffer test case failed.");
return false;
}
}
// Do null ByteBuffer test case
if (!nullByteBufferTest(theMac)) {
System.out.println("NULL ByteBuffer test case failed.");
@ -148,8 +166,9 @@ public class PBMacBuffer {
* @param theMac MAC object to test.
* @return true - test case passed; false - otherwise;
*/
protected boolean largeByteBufferTest(Mac theMac) {
ByteBuffer buf = generateRandomByteBuffer(LARGE_SIZE);
protected boolean largeByteBufferTest(Mac theMac,
Function<Integer, ByteBuffer> createBuffer) {
ByteBuffer buf = createBuffer.apply(LARGE_SIZE);
int limitBefore = buf.limit();
theMac.update(buf);
@ -179,8 +198,8 @@ public class PBMacBuffer {
* @param theMac
* @return true - test case pass; exception otherwise
*/
protected boolean emptyByteBufferTest(Mac theMac) {
ByteBuffer buf = generateRandomByteBuffer(0);
protected boolean emptyByteBufferTest(Mac theMac, Function<Integer, ByteBuffer> createBuffer) {
ByteBuffer buf = createBuffer.apply(0);
theMac.update(buf);
theMac.doFinal();
return true;