8318756: Create better internal buffer for AEADs
Reviewed-by: djelinski
This commit is contained in:
parent
a9cb120d03
commit
dc9c77bebe
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sun.crypto.provider;
|
||||||
|
|
||||||
|
import jdk.internal.util.ArraysSupport;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HexFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class extends ByteArrayOutputStream by optimizing internal buffering.
|
||||||
|
* It skips bounds checking, as the buffers are known and input previously
|
||||||
|
* checked. toByteArray() returns the internal buffer to avoid an extra copy.
|
||||||
|
*
|
||||||
|
* This uses `count` to determine the state of `buf`. `buf` can still
|
||||||
|
* point to an array while `count` equals zero.
|
||||||
|
*/
|
||||||
|
final class AEADBufferedStream extends ByteArrayOutputStream {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance with the specified buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
public AEADBufferedStream(int len) {
|
||||||
|
super(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method saves memory by returning the internal buffer. The calling
|
||||||
|
* method must use {@code size()} for the relevant data length as the
|
||||||
|
* returning byte[] maybe larger.
|
||||||
|
*
|
||||||
|
* @return internal buffer.
|
||||||
|
*/
|
||||||
|
public byte[] getBuffer() {
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method with expand the buffer if {@code count} + {@code len}
|
||||||
|
* is larger than the buffer byte[] length.
|
||||||
|
* @param len length to add to the current buffer
|
||||||
|
*/
|
||||||
|
private void checkCapacity(int len) {
|
||||||
|
int blen = buf.length;
|
||||||
|
// Create a new larger buffer and append the new data
|
||||||
|
if (blen < count + len) {
|
||||||
|
buf = Arrays.copyOf(buf, ArraysSupport.newLength(blen, len, blen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a ByteBuffer writing non-blocksize data directly to the internal
|
||||||
|
* buffer.
|
||||||
|
* @param src remaining non-blocksize ByteBuffer
|
||||||
|
*/
|
||||||
|
public void write(ByteBuffer src) {
|
||||||
|
int pos = src.position();
|
||||||
|
int len = src.remaining();
|
||||||
|
|
||||||
|
if (src.hasArray()) {
|
||||||
|
write(src.array(), pos + src.arrayOffset(), len);
|
||||||
|
src.position(pos + len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCapacity(len);
|
||||||
|
src.get(buf, count, len);
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] in, int offset, int len) {
|
||||||
|
checkCapacity(len);
|
||||||
|
System.arraycopy(in, offset, buf, count, len);
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return (count == 0 ? "null" : HexFormat.of().formatHex(buf));
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package com.sun.crypto.provider;
|
package com.sun.crypto.provider;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
@ -64,7 +63,6 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
private static final int KS_MAX_LEN = 1024;
|
private static final int KS_MAX_LEN = 1024;
|
||||||
private static final int KS_BLK_SIZE = 64;
|
private static final int KS_BLK_SIZE = 64;
|
||||||
private static final int KS_SIZE_INTS = KS_BLK_SIZE / Integer.BYTES;
|
private static final int KS_SIZE_INTS = KS_BLK_SIZE / Integer.BYTES;
|
||||||
private static final int CIPHERBUF_BASE = 1024;
|
|
||||||
|
|
||||||
// The initialization state of the cipher
|
// The initialization state of the cipher
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
@ -650,7 +648,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
try {
|
try {
|
||||||
engine.doUpdate(in, inOfs, inLen, out, 0);
|
engine.doUpdate(in, inOfs, inLen, out, 0);
|
||||||
} catch (ShortBufferException | KeyException exc) {
|
} catch (ShortBufferException | KeyException exc) {
|
||||||
throw new RuntimeException(exc);
|
throw new ProviderException(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
@ -681,11 +679,35 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
try {
|
try {
|
||||||
bytesUpdated = engine.doUpdate(in, inOfs, inLen, out, outOfs);
|
bytesUpdated = engine.doUpdate(in, inOfs, inLen, out, outOfs);
|
||||||
} catch (KeyException ke) {
|
} catch (KeyException ke) {
|
||||||
throw new RuntimeException(ke);
|
throw new ProviderException(ke);
|
||||||
}
|
}
|
||||||
return bytesUpdated;
|
return bytesUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the currently running operation with additional data
|
||||||
|
*
|
||||||
|
* @param input the plaintext or ciphertext ByteBuffer
|
||||||
|
* @param output ByteBuffer that will hold the resulting data. This
|
||||||
|
* must be large enough to hold the resulting data.
|
||||||
|
*
|
||||||
|
* @return the length in bytes of the data written into the {@code out}
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* @throws ShortBufferException if the buffer {@code out} does not have
|
||||||
|
* enough space to hold the resulting data.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected int engineUpdate(ByteBuffer input, ByteBuffer output)
|
||||||
|
throws ShortBufferException {
|
||||||
|
try {
|
||||||
|
return bufferCrypt(input, output, true);
|
||||||
|
} catch (AEADBadTagException e) {
|
||||||
|
// exception is never thrown by update ops
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Complete the currently running operation using any final
|
* Complete the currently running operation using any final
|
||||||
* data provided by the caller.
|
* data provided by the caller.
|
||||||
@ -753,6 +775,118 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
return bytesUpdated;
|
return bytesUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete the currently running operation using any final
|
||||||
|
* data provided by the caller.
|
||||||
|
*
|
||||||
|
* @param input the plaintext or ciphertext input bytebuffer.
|
||||||
|
* @param output ByteBuffer that will hold the resulting data. This
|
||||||
|
* must be large enough to hold the resulting data.
|
||||||
|
*
|
||||||
|
* @return the resulting plaintext or ciphertext bytes.
|
||||||
|
*
|
||||||
|
* @throws AEADBadTagException if, during decryption, the provided tag
|
||||||
|
* does not match the calculated tag.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected int engineDoFinal(ByteBuffer input, ByteBuffer output)
|
||||||
|
throws ShortBufferException, AEADBadTagException {
|
||||||
|
return bufferCrypt(input, output, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optimized version of bufferCrypt from CipherSpi.java. Direct
|
||||||
|
* ByteBuffers send to the engine code.
|
||||||
|
*/
|
||||||
|
private int bufferCrypt(ByteBuffer input, ByteBuffer output,
|
||||||
|
boolean isUpdate) throws ShortBufferException, AEADBadTagException {
|
||||||
|
if ((input == null) || (output == null)) {
|
||||||
|
throw new NullPointerException
|
||||||
|
("Input and output buffers must not be null");
|
||||||
|
}
|
||||||
|
int inPos = input.position();
|
||||||
|
int inLimit = input.limit();
|
||||||
|
int inLen = inLimit - inPos;
|
||||||
|
if (isUpdate && (inLen == 0)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int outLenNeeded = engine.getOutputSize(inLen, !isUpdate);
|
||||||
|
|
||||||
|
if (output.remaining() < outLenNeeded) {
|
||||||
|
throw new ShortBufferException("Need at least " + outLenNeeded
|
||||||
|
+ " bytes of space in output buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
// Check if input bytebuffer is heap-backed
|
||||||
|
if (input.hasArray()) {
|
||||||
|
byte[] inArray = input.array();
|
||||||
|
int inOfs = input.arrayOffset() + inPos;
|
||||||
|
|
||||||
|
byte[] outArray;
|
||||||
|
// Check if output bytebuffer is heap-backed
|
||||||
|
if (output.hasArray()) {
|
||||||
|
outArray = output.array();
|
||||||
|
int outPos = output.position();
|
||||||
|
int outOfs = output.arrayOffset() + outPos;
|
||||||
|
|
||||||
|
// check array address and offsets and use temp output buffer
|
||||||
|
// if output offset is larger than input offset and
|
||||||
|
// falls within the range of input data
|
||||||
|
boolean useTempOut = false;
|
||||||
|
if (inArray == outArray &&
|
||||||
|
((inOfs < outOfs) && (outOfs < inOfs + inLen))) {
|
||||||
|
useTempOut = true;
|
||||||
|
outArray = new byte[outLenNeeded];
|
||||||
|
outOfs = 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (isUpdate) {
|
||||||
|
total = engine.doUpdate(inArray, inOfs, inLen, outArray,
|
||||||
|
outOfs);
|
||||||
|
} else {
|
||||||
|
total = engine.doFinal(inArray, inOfs, inLen, outArray,
|
||||||
|
outOfs);
|
||||||
|
}
|
||||||
|
} catch (KeyException e) {
|
||||||
|
throw new ProviderException(e);
|
||||||
|
}
|
||||||
|
if (useTempOut) {
|
||||||
|
output.put(outArray, outOfs, total);
|
||||||
|
} else {
|
||||||
|
// adjust output position manually
|
||||||
|
output.position(outPos + total);
|
||||||
|
}
|
||||||
|
} else { // if output is direct
|
||||||
|
if (isUpdate) {
|
||||||
|
outArray = engineUpdate(inArray, inOfs, inLen);
|
||||||
|
} else {
|
||||||
|
outArray = engineDoFinal(inArray, inOfs, inLen);
|
||||||
|
}
|
||||||
|
if (outArray != null && outArray.length != 0) {
|
||||||
|
output.put(outArray);
|
||||||
|
total = outArray.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// adjust input position manually
|
||||||
|
input.position(inLimit);
|
||||||
|
} else { // Bytebuffers are both direct
|
||||||
|
try {
|
||||||
|
if (isUpdate) {
|
||||||
|
return engine.doUpdate(input, output);
|
||||||
|
}
|
||||||
|
return engine.doFinal(input, output);
|
||||||
|
} catch (KeyException e) {
|
||||||
|
throw new ProviderException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap a {@code Key} using this Cipher's current encryption parameters.
|
* Wrap a {@code Key} using this Cipher's current encryption parameters.
|
||||||
*
|
*
|
||||||
@ -1243,6 +1377,11 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
*/
|
*/
|
||||||
int doFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)
|
int doFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)
|
||||||
throws ShortBufferException, AEADBadTagException, KeyException;
|
throws ShortBufferException, AEADBadTagException, KeyException;
|
||||||
|
|
||||||
|
int doUpdate(ByteBuffer input, ByteBuffer output) throws
|
||||||
|
ShortBufferException, KeyException;
|
||||||
|
int doFinal(ByteBuffer input, ByteBuffer output) throws
|
||||||
|
ShortBufferException, KeyException, AEADBadTagException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class EngineStreamOnly implements ChaChaEngine {
|
private final class EngineStreamOnly implements ChaChaEngine {
|
||||||
@ -1285,6 +1424,22 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
int outOff) throws ShortBufferException, KeyException {
|
int outOff) throws ShortBufferException, KeyException {
|
||||||
return doUpdate(in, inOff, inLen, out, outOff);
|
return doUpdate(in, inOff, inLen, out, outOff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int doUpdate(ByteBuffer input, ByteBuffer output) throws
|
||||||
|
ShortBufferException, KeyException {
|
||||||
|
byte[] data = new byte[input.remaining()];
|
||||||
|
input.get(data);
|
||||||
|
doUpdate(data, 0, data.length, data, 0);
|
||||||
|
output.put(data);
|
||||||
|
return data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int doFinal(ByteBuffer input, ByteBuffer output)
|
||||||
|
throws ShortBufferException, KeyException {
|
||||||
|
return doUpdate(input, output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class EngineAEADEnc implements ChaChaEngine {
|
private final class EngineAEADEnc implements ChaChaEngine {
|
||||||
@ -1348,11 +1503,32 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
aadDone = false;
|
aadDone = false;
|
||||||
return inLen + TAG_LENGTH;
|
return inLen + TAG_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int doUpdate(ByteBuffer input, ByteBuffer output) throws
|
||||||
|
ShortBufferException, KeyException {
|
||||||
|
byte[] data = new byte[input.remaining()];
|
||||||
|
input.get(data);
|
||||||
|
doUpdate(data, 0, data.length, data, 0);
|
||||||
|
output.put(data);
|
||||||
|
return data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int doFinal(ByteBuffer input, ByteBuffer output) throws
|
||||||
|
ShortBufferException, KeyException {
|
||||||
|
int len = input.remaining();
|
||||||
|
byte[] data = new byte[len + TAG_LENGTH];
|
||||||
|
input.get(data, 0, len);
|
||||||
|
doFinal(data, 0, len, data, 0);
|
||||||
|
output.put(data);
|
||||||
|
return data.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class EngineAEADDec implements ChaChaEngine {
|
private final class EngineAEADDec implements ChaChaEngine {
|
||||||
|
|
||||||
private final ByteArrayOutputStream cipherBuf;
|
private AEADBufferedStream cipherBuf = null;
|
||||||
private final byte[] tag;
|
private final byte[] tag;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1364,14 +1540,26 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
// size.
|
// size.
|
||||||
return (isFinal ?
|
return (isFinal ?
|
||||||
Integer.max(Math.addExact((inLen - TAG_LENGTH),
|
Integer.max(Math.addExact((inLen - TAG_LENGTH),
|
||||||
cipherBuf.size()), 0) : 0);
|
getBufferedLength()), 0) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initBuffer(int len) {
|
||||||
|
if (cipherBuf == null) {
|
||||||
|
cipherBuf = new AEADBufferedStream(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getBufferedLength() {
|
||||||
|
if (cipherBuf != null) {
|
||||||
|
return cipherBuf.size();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EngineAEADDec() throws InvalidKeyException {
|
private EngineAEADDec() throws InvalidKeyException {
|
||||||
initAuthenticator();
|
initAuthenticator();
|
||||||
initCounterValue = 1;
|
initCounterValue = 1;
|
||||||
counter = initCounterValue;
|
counter = initCounterValue;
|
||||||
cipherBuf = new ByteArrayOutputStream(CIPHERBUF_BASE);
|
|
||||||
tag = new byte[TAG_LENGTH];
|
tag = new byte[TAG_LENGTH];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1389,6 +1577,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
|
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
Objects.checkFromIndexSize(inOff, inLen, in.length);
|
Objects.checkFromIndexSize(inOff, inLen, in.length);
|
||||||
|
initBuffer(inLen);
|
||||||
cipherBuf.write(in, inOff, inLen);
|
cipherBuf.write(in, inOff, inLen);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1399,6 +1588,14 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int doUpdate(ByteBuffer input, ByteBuffer output) {
|
||||||
|
initBuffer(input.remaining());
|
||||||
|
cipherBuf.write(input);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int doFinal(byte[] in, int inOff, int inLen, byte[] out,
|
public int doFinal(byte[] in, int inOff, int inLen, byte[] out,
|
||||||
int outOff) throws ShortBufferException, AEADBadTagException,
|
int outOff) throws ShortBufferException, AEADBadTagException,
|
||||||
@ -1406,7 +1603,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
|
|
||||||
byte[] ctPlusTag;
|
byte[] ctPlusTag;
|
||||||
int ctPlusTagLen;
|
int ctPlusTagLen;
|
||||||
if (cipherBuf.size() == 0 && inOff == 0) {
|
if (getBufferedLength() == 0) {
|
||||||
// No previous data has been seen before doFinal, so we do
|
// No previous data has been seen before doFinal, so we do
|
||||||
// not need to hold any ciphertext in a buffer. We can
|
// not need to hold any ciphertext in a buffer. We can
|
||||||
// process it directly from the "in" parameter.
|
// process it directly from the "in" parameter.
|
||||||
@ -1415,10 +1612,11 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
ctPlusTagLen = inLen;
|
ctPlusTagLen = inLen;
|
||||||
} else {
|
} else {
|
||||||
doUpdate(in, inOff, inLen, out, outOff);
|
doUpdate(in, inOff, inLen, out, outOff);
|
||||||
ctPlusTag = cipherBuf.toByteArray();
|
ctPlusTag = cipherBuf.getBuffer();
|
||||||
ctPlusTagLen = ctPlusTag.length;
|
inOff = 0;
|
||||||
}
|
ctPlusTagLen = cipherBuf.size();
|
||||||
cipherBuf.reset();
|
cipherBuf.reset();
|
||||||
|
}
|
||||||
|
|
||||||
// There must at least be a tag length's worth of ciphertext
|
// There must at least be a tag length's worth of ciphertext
|
||||||
// data in the buffered input.
|
// data in the buffered input.
|
||||||
@ -1436,19 +1634,80 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||||||
|
|
||||||
// Calculate and compare the tag. Only do the decryption
|
// Calculate and compare the tag. Only do the decryption
|
||||||
// if and only if the tag matches.
|
// if and only if the tag matches.
|
||||||
authFinalizeData(ctPlusTag, 0, ctLen, tag, 0);
|
authFinalizeData(ctPlusTag, inOff, ctLen, tag, 0);
|
||||||
long tagCompare = ((long)asLongView.get(ctPlusTag, ctLen) ^
|
long tagCompare = ((long)asLongView.get(ctPlusTag, ctLen + inOff) ^
|
||||||
(long)asLongView.get(tag, 0)) |
|
(long)asLongView.get(tag, 0)) |
|
||||||
((long)asLongView.get(ctPlusTag, ctLen + Long.BYTES) ^
|
((long)asLongView.get(ctPlusTag, ctLen + inOff + Long.BYTES) ^
|
||||||
(long)asLongView.get(tag, Long.BYTES));
|
(long)asLongView.get(tag, Long.BYTES));
|
||||||
if (tagCompare != 0) {
|
if (tagCompare != 0) {
|
||||||
throw new AEADBadTagException("Tag mismatch");
|
throw new AEADBadTagException("Tag mismatch");
|
||||||
}
|
}
|
||||||
chaCha20Transform(ctPlusTag, 0, ctLen, out, outOff);
|
chaCha20Transform(ctPlusTag, inOff, ctLen, out, outOff);
|
||||||
aadDone = false;
|
aadDone = false;
|
||||||
|
|
||||||
return ctLen;
|
return ctLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int doFinal(ByteBuffer input, ByteBuffer output)
|
||||||
|
throws ShortBufferException, AEADBadTagException, KeyException {
|
||||||
|
int len;
|
||||||
|
int inLen = input.remaining();
|
||||||
|
byte[] ct = null, buf = null;
|
||||||
|
//buf = (getBufferedLength() == 0 ? null : cipherBuf.toByteArray());
|
||||||
|
int bufLen = 0;
|
||||||
|
// The length of cipher text and tag
|
||||||
|
int ctLen = getBufferedLength() + inLen;
|
||||||
|
|
||||||
|
if (ctLen < TAG_LENGTH) {
|
||||||
|
throw new AEADBadTagException("Input too short - need tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inLen < TAG_LENGTH) {
|
||||||
|
if (inLen > 0) {
|
||||||
|
doUpdate(input, output);
|
||||||
|
}
|
||||||
|
if (cipherBuf != null) {
|
||||||
|
ct = cipherBuf.getBuffer();
|
||||||
|
}
|
||||||
|
len = ctLen;
|
||||||
|
} else {
|
||||||
|
if (cipherBuf != null) {
|
||||||
|
buf = cipherBuf.getBuffer();
|
||||||
|
bufLen = cipherBuf.size();
|
||||||
|
}
|
||||||
|
ct = new byte[inLen];
|
||||||
|
input.get(ct, 0, inLen);
|
||||||
|
len = inLen;
|
||||||
|
}
|
||||||
|
doUpdate(null, 0, 0, null, 0);
|
||||||
|
|
||||||
|
// If there is an internal buffer, calculate its tag contribution.
|
||||||
|
if (buf != null) {
|
||||||
|
dataLen = authUpdate(buf, 0, bufLen);
|
||||||
|
}
|
||||||
|
// Complete tag calculation
|
||||||
|
len -= TAG_LENGTH;
|
||||||
|
authFinalizeData(ct, 0, len, tag, 0);
|
||||||
|
// Check tag
|
||||||
|
if ((((long) asLongView.get(ct, len) ^
|
||||||
|
(long) asLongView.get(tag, 0)) |
|
||||||
|
((long) asLongView.get(ct, len + Long.BYTES) ^
|
||||||
|
(long) asLongView.get(tag, Long.BYTES))) != 0) {
|
||||||
|
throw new AEADBadTagException("Tag mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt internal buffer in-place, then put it into the bytebuffer
|
||||||
|
if (buf != null) {
|
||||||
|
chaCha20Transform(buf, 0, bufLen, buf, 0);
|
||||||
|
output.put(buf, 0, bufLen);
|
||||||
|
}
|
||||||
|
// decrypt input buffer in-place, append it to the bytebuffer
|
||||||
|
chaCha20Transform(ct, 0, len, ct, 0);
|
||||||
|
output.put(ct, 0, len);
|
||||||
|
aadDone = false;
|
||||||
|
return ctLen - TAG_LENGTH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class ChaCha20Only extends ChaCha20Cipher {
|
public static final class ChaCha20Only extends ChaCha20Cipher {
|
||||||
|
@ -40,8 +40,6 @@ import javax.crypto.IllegalBlockSizeException;
|
|||||||
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.NoSuchPaddingException;
|
||||||
import javax.crypto.ShortBufferException;
|
import javax.crypto.ShortBufferException;
|
||||||
import javax.crypto.spec.GCMParameterSpec;
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -249,7 +247,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
protected AlgorithmParameters engineGetParameters() {
|
protected AlgorithmParameters engineGetParameters() {
|
||||||
GCMParameterSpec spec;
|
GCMParameterSpec spec;
|
||||||
spec = new GCMParameterSpec(tagLenBytes * 8,
|
spec = new GCMParameterSpec(tagLenBytes * 8,
|
||||||
iv == null ? createIv(random) : iv.clone());
|
iv == null ? createIv(random) : iv); // iv.clone() not necessary
|
||||||
try {
|
try {
|
||||||
AlgorithmParameters params =
|
AlgorithmParameters params =
|
||||||
AlgorithmParameters.getInstance("GCM",
|
AlgorithmParameters.getInstance("GCM",
|
||||||
@ -680,12 +678,12 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
final int blockSize;
|
final int blockSize;
|
||||||
|
|
||||||
// buffer for AAD data; if null, meaning update has been called
|
// buffer for AAD data; if null, meaning update has been called
|
||||||
ByteArrayOutputStream aadBuffer = null;
|
AEADBufferedStream aadBuffer = null;
|
||||||
int sizeOfAAD = 0;
|
int sizeOfAAD = 0;
|
||||||
boolean aadProcessed = false;
|
boolean aadProcessed = false;
|
||||||
|
|
||||||
// buffer data for crypto operation
|
// buffer data for crypto operation
|
||||||
ByteArrayOutputStream ibuffer = null;
|
AEADBufferedStream ibuffer = null;
|
||||||
|
|
||||||
// Original dst buffer if there was an overlap situation
|
// Original dst buffer if there was an overlap situation
|
||||||
ByteBuffer originalDst = null;
|
ByteBuffer originalDst = null;
|
||||||
@ -736,7 +734,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
// Initialize internal data buffer, if not already.
|
// Initialize internal data buffer, if not already.
|
||||||
void initBuffer(int len) {
|
void initBuffer(int len) {
|
||||||
if (ibuffer == null) {
|
if (ibuffer == null) {
|
||||||
ibuffer = new ByteArrayOutputStream(len);
|
ibuffer = new AEADBufferedStream(len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,20 +786,6 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The method takes two buffers to create one block of data. The
|
|
||||||
* difference with the other mergeBlock is this will calculate
|
|
||||||
* the bufLen from the existing 'buffer' length & offset
|
|
||||||
*
|
|
||||||
* This is only called when buffer length is less than a blockSize
|
|
||||||
* @return number of bytes used from 'in'
|
|
||||||
*/
|
|
||||||
int mergeBlock(byte[] buffer, int bufOfs, byte[] in, int inOfs,
|
|
||||||
int inLen, byte[] block) {
|
|
||||||
return mergeBlock(buffer, bufOfs, buffer.length - bufOfs, in,
|
|
||||||
inOfs, inLen, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method takes two buffers to create one block of data
|
* The method takes two buffers to create one block of data
|
||||||
*
|
*
|
||||||
@ -822,7 +806,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continues a multi-part update of the Additional Authentication
|
* Continues a multipart update of the Additional Authentication
|
||||||
* Data (AAD), using a subset of the provided buffer. All AAD must be
|
* Data (AAD), using a subset of the provided buffer. All AAD must be
|
||||||
* supplied before beginning operations on the ciphertext (via the
|
* supplied before beginning operations on the ciphertext (via the
|
||||||
* {@code update} and {@code doFinal} methods).
|
* {@code update} and {@code doFinal} methods).
|
||||||
@ -843,7 +827,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
|
|
||||||
if (aadBuffer == null) {
|
if (aadBuffer == null) {
|
||||||
if (sizeOfAAD == 0 && !aadProcessed) {
|
if (sizeOfAAD == 0 && !aadProcessed) {
|
||||||
aadBuffer = new ByteArrayOutputStream(len);
|
aadBuffer = new AEADBufferedStream(len);
|
||||||
} else {
|
} else {
|
||||||
// update has already been called
|
// update has already been called
|
||||||
throw new IllegalStateException
|
throw new IllegalStateException
|
||||||
@ -856,18 +840,17 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
// Feed the AAD data to GHASH, pad if necessary
|
// Feed the AAD data to GHASH, pad if necessary
|
||||||
void processAAD() {
|
void processAAD() {
|
||||||
if (aadBuffer != null) {
|
if (aadBuffer != null) {
|
||||||
if (aadBuffer.size() > 0) {
|
sizeOfAAD = aadBuffer.size();
|
||||||
byte[] aad = aadBuffer.toByteArray();
|
if (sizeOfAAD > 0) {
|
||||||
sizeOfAAD = aad.length;
|
byte[] aad = aadBuffer.getBuffer();
|
||||||
|
int lastLen = sizeOfAAD % blockSize;
|
||||||
int lastLen = aad.length % blockSize;
|
|
||||||
if (lastLen != 0) {
|
if (lastLen != 0) {
|
||||||
ghash.update(aad, 0, aad.length - lastLen);
|
ghash.update(aad, 0, sizeOfAAD - lastLen);
|
||||||
byte[] padded = expandToOneBlock(aad,
|
byte[] padded = expandToOneBlock(aad,
|
||||||
aad.length - lastLen, lastLen, blockSize);
|
sizeOfAAD - lastLen, lastLen, blockSize);
|
||||||
ghash.update(padded);
|
ghash.update(padded);
|
||||||
} else {
|
} else {
|
||||||
ghash.update(aad);
|
ghash.update(aad, 0, sizeOfAAD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aadBuffer = null;
|
aadBuffer = null;
|
||||||
@ -1147,7 +1130,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
|
|
||||||
// if there is enough data in the ibuffer and 'in', encrypt it.
|
// if there is enough data in the ibuffer and 'in', encrypt it.
|
||||||
if (bLen > 0) {
|
if (bLen > 0) {
|
||||||
byte[] buffer = ibuffer.toByteArray();
|
byte[] buffer = ibuffer.getBuffer();
|
||||||
// number of bytes not filling a block
|
// number of bytes not filling a block
|
||||||
int remainder = blockSize - bLen;
|
int remainder = blockSize - bLen;
|
||||||
|
|
||||||
@ -1167,7 +1150,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt the remaining blocks inside of 'in'
|
// Encrypt the remaining blocks inside 'in'
|
||||||
if (inLen >= PARALLEL_LEN) {
|
if (inLen >= PARALLEL_LEN) {
|
||||||
int r = GaloisCounterMode.implGCMCrypt(in, inOfs, inLen, out,
|
int r = GaloisCounterMode.implGCMCrypt(in, inOfs, inLen, out,
|
||||||
outOfs, out, outOfs, gctr, ghash);
|
outOfs, out, outOfs, gctr, ghash);
|
||||||
@ -1223,7 +1206,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
// Check if there is enough 'src' and 'buffer' to fill a block
|
// Check if there is enough 'src' and 'buffer' to fill a block
|
||||||
if (src.remaining() >= remainder) {
|
if (src.remaining() >= remainder) {
|
||||||
byte[] block = new byte[blockSize];
|
byte[] block = new byte[blockSize];
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(ibuffer.toByteArray());
|
ByteBuffer buffer = ByteBuffer.wrap(ibuffer.getBuffer(),
|
||||||
|
0, ibuffer.size());
|
||||||
buffer.get(block, 0, bLen);
|
buffer.get(block, 0, bLen);
|
||||||
src.get(block, bLen, remainder);
|
src.get(block, bLen, remainder);
|
||||||
len += op.update(ByteBuffer.wrap(block, 0, blockSize),
|
len += op.update(ByteBuffer.wrap(block, 0, blockSize),
|
||||||
@ -1251,14 +1235,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
// Write the remaining bytes into the 'ibuffer'
|
// Write the remaining bytes into the 'ibuffer'
|
||||||
if (srcLen > 0) {
|
if (srcLen > 0) {
|
||||||
initBuffer(srcLen);
|
initBuffer(srcLen);
|
||||||
byte[] b = new byte[srcLen];
|
|
||||||
src.get(b);
|
|
||||||
// remainder offset is based on original buffer length
|
// remainder offset is based on original buffer length
|
||||||
try {
|
ibuffer.write(src);
|
||||||
ibuffer.write(b);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreDst(dst);
|
restoreDst(dst);
|
||||||
@ -1290,13 +1268,13 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
|
|
||||||
// process what is in the ibuffer
|
// process what is in the ibuffer
|
||||||
if (bLen > 0) {
|
if (bLen > 0) {
|
||||||
byte[] buffer = ibuffer.toByteArray();
|
byte[] buffer = ibuffer.getBuffer();
|
||||||
|
|
||||||
// Make a block if the remaining ibuffer and 'in' can make one.
|
// Make a block if the remaining ibuffer and 'in' can make one.
|
||||||
if (bLen + inLen >= blockSize) {
|
if (bLen + inLen >= blockSize) {
|
||||||
int r;
|
int r;
|
||||||
block = new byte[blockSize];
|
block = new byte[blockSize];
|
||||||
r = mergeBlock(buffer, 0, in, inOfs, inLen, block);
|
r = mergeBlock(buffer, 0, ibuffer.size(), in, inOfs, inLen, block);
|
||||||
inOfs += r;
|
inOfs += r;
|
||||||
inLen -= r;
|
inLen -= r;
|
||||||
op.update(block, 0, blockSize, out, outOfs);
|
op.update(block, 0, blockSize, out, outOfs);
|
||||||
@ -1353,7 +1331,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
processed += doLastBlock(op,
|
processed += doLastBlock(op,
|
||||||
(ibuffer == null || ibuffer.size() == 0) ? null :
|
(ibuffer == null || ibuffer.size() == 0) ? null :
|
||||||
ByteBuffer.wrap(ibuffer.toByteArray()), src, dst);
|
ByteBuffer.wrap(ibuffer.getBuffer(), 0,
|
||||||
|
ibuffer.size()), src, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
// release buffer if needed
|
// release buffer if needed
|
||||||
@ -1427,9 +1406,10 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
tagLenBytes);
|
tagLenBytes);
|
||||||
} else {
|
} else {
|
||||||
// tagOfs will be negative
|
// tagOfs will be negative
|
||||||
byte[] buffer = ibuffer.toByteArray();
|
byte[] buffer = ibuffer.getBuffer();
|
||||||
tagOfs = mergeBlock(buffer,
|
int ofs = ibuffer.size() - (tagLenBytes - inLen);
|
||||||
buffer.length - (tagLenBytes - inLen), in, inOfs, inLen,
|
tagOfs = mergeBlock(buffer, ofs, ibuffer.size() - ofs,
|
||||||
|
in, inOfs, inLen,
|
||||||
tag) - tagLenBytes;
|
tag) - tagLenBytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1475,15 +1455,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
src.remaining(), null, 0);
|
src.remaining(), null, 0);
|
||||||
src.position(src.limit());
|
src.position(src.limit());
|
||||||
} else {
|
} else {
|
||||||
byte[] b = new byte[src.remaining()];
|
initBuffer(src.remaining());
|
||||||
src.get(b);
|
ibuffer.write(src);
|
||||||
initBuffer(b.length);
|
|
||||||
try {
|
|
||||||
ibuffer.write(b);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ProviderException(
|
|
||||||
"Unable to add remaining input to the buffer", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1491,7 +1464,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Use available data from ibuffer and 'in' to verify and decrypt the
|
* Use available data from ibuffer and 'in' to verify and decrypt the
|
||||||
* data. If the verification fails, the 'out' left to it's original
|
* data. If the verification fails, the 'out' left to its original
|
||||||
* values if crypto was in-place; otherwise 'out' is zeroed
|
* values if crypto was in-place; otherwise 'out' is zeroed
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -1551,7 +1524,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Use available data from ibuffer and 'src' to verify and decrypt the
|
* Use available data from ibuffer and 'src' to verify and decrypt the
|
||||||
* data. If the verification fails, the 'dst' left to it's original
|
* data. If the verification fails, the 'dst' left to its original
|
||||||
* values if crypto was in-place; otherwise 'dst' is zeroed
|
* values if crypto was in-place; otherwise 'dst' is zeroed
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -1568,7 +1541,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
|
|
||||||
// Check if ibuffer has data
|
// Check if ibuffer has data
|
||||||
if (getBufferedLength() != 0) {
|
if (getBufferedLength() != 0) {
|
||||||
buffer = ByteBuffer.wrap(ibuffer.toByteArray());
|
buffer = ByteBuffer.wrap(ibuffer.getBuffer(), 0,
|
||||||
|
ibuffer.size());
|
||||||
len += buffer.remaining();
|
len += buffer.remaining();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1684,7 +1658,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bLen > 0) {
|
if (bLen > 0) {
|
||||||
buffer = ibuffer.toByteArray();
|
buffer = ibuffer.getBuffer();
|
||||||
|
|
||||||
if (bLen >= PARALLEL_LEN) {
|
if (bLen >= PARALLEL_LEN) {
|
||||||
len = GaloisCounterMode.implGCMCrypt(buffer, 0, bLen,
|
len = GaloisCounterMode.implGCMCrypt(buffer, 0, bLen,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -34,16 +34,18 @@
|
|||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.GCMParameterSpec;
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HexFormat;
|
import java.util.HexFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GCMBufferTest implements Cloneable {
|
public class AEADBufferTest implements Cloneable {
|
||||||
|
|
||||||
// Data type for the operation
|
// Data type for the operation
|
||||||
enum dtype { BYTE, HEAP, DIRECT };
|
enum dtype { BYTE, HEAP, DIRECT };
|
||||||
@ -52,7 +54,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
// List of enum values for order of operation
|
// List of enum values for order of operation
|
||||||
List<dtype> ops;
|
List<dtype> ops;
|
||||||
|
|
||||||
static final int AESBLOCK = 16;
|
static final String AES = "AES";
|
||||||
// The remaining input data length is inserted at the particular index
|
// The remaining input data length is inserted at the particular index
|
||||||
// in sizes[] during execution.
|
// in sizes[] during execution.
|
||||||
static final int REMAINDER = -1;
|
static final int REMAINDER = -1;
|
||||||
@ -71,20 +73,16 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
int id;
|
int id;
|
||||||
SecretKey key;
|
SecretKey key;
|
||||||
byte[] iv;
|
byte[] iv;
|
||||||
|
int counter; // for CC20
|
||||||
byte[] pt;
|
byte[] pt;
|
||||||
byte[] aad;
|
byte[] aad;
|
||||||
byte[] ct;
|
byte[] ct;
|
||||||
byte[] tag;
|
byte[] tag;
|
||||||
|
int blockSize; // 16 for GCM, 0 for CC20
|
||||||
|
|
||||||
Data(String keyalgo, int id, String key, String iv, byte[] pt, String aad,
|
Data(String keyalgo, int id, String key, String iv, byte[] pt, String aad,
|
||||||
String ct, String tag) {
|
String ct, String tag) {
|
||||||
this.id = id;
|
this(keyalgo, id, key, iv, 0,pt, aad, ct,tag);
|
||||||
this.key = new SecretKeySpec(HexToBytes(key), keyalgo);
|
|
||||||
this.iv = HexToBytes(iv);
|
|
||||||
this.pt = pt;
|
|
||||||
this.aad = HexToBytes(aad);
|
|
||||||
this.ct = HexToBytes(ct);
|
|
||||||
this.tag = HexToBytes(tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Data(String keyalgo, int id, String key, String iv, String pt, String aad,
|
Data(String keyalgo, int id, String key, String iv, String pt, String aad,
|
||||||
@ -92,21 +90,42 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
this(keyalgo, id, key, iv, HexToBytes(pt), aad, ct, tag);
|
this(keyalgo, id, key, iv, HexToBytes(pt), aad, ct, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
Data(String keyalgo, int id, String key, int ptlen) {
|
Data(String keyalgo, int id, String key, String iv, int counter, byte[] pt, String aad,
|
||||||
|
String ct, String tag) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.key = new SecretKeySpec(HexToBytes(key), keyalgo);
|
this.key = new SecretKeySpec(HexToBytes(key), keyalgo);
|
||||||
iv = new byte[16];
|
this.iv = HexToBytes(iv);
|
||||||
|
this.counter = counter;
|
||||||
|
this.pt = pt;
|
||||||
|
this.aad = HexToBytes(aad);
|
||||||
|
this.ct = HexToBytes(ct);
|
||||||
|
this.tag = HexToBytes(tag);
|
||||||
|
this.blockSize = (keyalgo.equals(AES) ? 16 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Data(String keyalgo, int id, String key, String iv, int counter, String pt, String aad,
|
||||||
|
String ct, String tag) {
|
||||||
|
this(keyalgo, id, key, iv, counter, HexToBytes(pt), aad, ct, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
Data(String keyalgo, int id, String key, int ivLen, int ptlen) {
|
||||||
|
this.id = id;
|
||||||
|
this.key = new SecretKeySpec(HexToBytes(key), keyalgo);
|
||||||
|
iv = new byte[ivLen];
|
||||||
|
counter = 0;
|
||||||
pt = new byte[ptlen];
|
pt = new byte[ptlen];
|
||||||
tag = new byte[12];
|
tag = new byte[16];
|
||||||
aad = new byte[0];
|
aad = new byte[0];
|
||||||
|
boolean isGCM = keyalgo.equals(AES);
|
||||||
|
this.blockSize = (isGCM ? 16 : 0);
|
||||||
byte[] tct = null;
|
byte[] tct = null;
|
||||||
try {
|
try {
|
||||||
SecureRandom r = new SecureRandom();
|
SecureRandom r = new SecureRandom();
|
||||||
r.nextBytes(iv);
|
r.nextBytes(iv);
|
||||||
r.nextBytes(pt);
|
r.nextBytes(pt);
|
||||||
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
|
Cipher c = Cipher.getInstance(isGCM ? "AES/GCM/NoPadding": "ChaCha20-Poly1305");
|
||||||
c.init(Cipher.ENCRYPT_MODE, this.key,
|
c.init(Cipher.ENCRYPT_MODE, this.key,
|
||||||
new GCMParameterSpec(tag.length * 8, this.iv));
|
getAPS(keyalgo, tag.length, iv));
|
||||||
tct = c.doFinal(pt);
|
tct = c.doFinal(pt);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Error in generating data for length " +
|
throw new RuntimeException("Error in generating data for length " +
|
||||||
@ -117,7 +136,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
System.arraycopy(tct, ct.length, tag, 0, tag.length);
|
System.arraycopy(tct, ct.length, tag, 0, tag.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final byte[] HexToBytes(String hexVal) {
|
private static byte[] HexToBytes(String hexVal) {
|
||||||
if (hexVal == null) {
|
if (hexVal == null) {
|
||||||
return new byte[0];
|
return new byte[0];
|
||||||
}
|
}
|
||||||
@ -133,15 +152,15 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
* doFinal operation will occur. If multiple dtypes are
|
* doFinal operation will occur. If multiple dtypes are
|
||||||
* specified, the last is a doFinal, the others are updates.
|
* specified, the last is a doFinal, the others are updates.
|
||||||
*/
|
*/
|
||||||
GCMBufferTest(String algo, List<dtype> ops) {
|
AEADBufferTest(String algo, List<dtype> ops) {
|
||||||
this.algo = algo;
|
this.algo = algo;
|
||||||
this.ops = ops;
|
this.ops = ops;
|
||||||
theoreticalCheck = true;
|
theoreticalCheck = true;
|
||||||
dataSet = datamap.get(algo);
|
dataSet = datamap.get(algo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GCMBufferTest clone() throws CloneNotSupportedException{
|
public AEADBufferTest clone() throws CloneNotSupportedException{
|
||||||
return (GCMBufferTest)super.clone();
|
return (AEADBufferTest)super.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -150,7 +169,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
* that index during execution.
|
* that index during execution.
|
||||||
* @param sizes Data sizes for each dtype in the list.
|
* @param sizes Data sizes for each dtype in the list.
|
||||||
*/
|
*/
|
||||||
GCMBufferTest dataSegments(int[] sizes) {
|
AEADBufferTest dataSegments(int[] sizes) {
|
||||||
this.sizes = sizes;
|
this.sizes = sizes;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -158,7 +177,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
/**
|
/**
|
||||||
* Do not perform in-place operations
|
* Do not perform in-place operations
|
||||||
*/
|
*/
|
||||||
GCMBufferTest differentBufferOnly() {
|
AEADBufferTest differentBufferOnly() {
|
||||||
this.same = false;
|
this.same = false;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -167,7 +186,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
* Enable incrementing through each data size available. This can only be
|
* Enable incrementing through each data size available. This can only be
|
||||||
* used when the List has more than one dtype entry.
|
* used when the List has more than one dtype entry.
|
||||||
*/
|
*/
|
||||||
GCMBufferTest incrementalSegments() {
|
AEADBufferTest incrementalSegments() {
|
||||||
this.incremental = true;
|
this.incremental = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -177,7 +196,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
*
|
*
|
||||||
* @param id id value for the test data to used in this test.
|
* @param id id value for the test data to used in this test.
|
||||||
*/
|
*/
|
||||||
GCMBufferTest dataSet(int id) throws Exception {
|
AEADBufferTest dataSet(int id) throws Exception {
|
||||||
for (Data d : datamap.get(algo)) {
|
for (Data d : datamap.get(algo)) {
|
||||||
if (d.id == id) {
|
if (d.id == id) {
|
||||||
dataSet = List.of(d);
|
dataSet = List.of(d);
|
||||||
@ -192,7 +211,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
* @param offset value for inOfs and outOfs
|
* @param offset value for inOfs and outOfs
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
GCMBufferTest offset(int offset) {
|
AEADBufferTest offset(int offset) {
|
||||||
this.inOfs = offset;
|
this.inOfs = offset;
|
||||||
this.outOfs = offset;
|
this.outOfs = offset;
|
||||||
return this;
|
return this;
|
||||||
@ -201,9 +220,8 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
/**
|
/**
|
||||||
* Set the input offset
|
* Set the input offset
|
||||||
* @param offset value for input offset
|
* @param offset value for input offset
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
GCMBufferTest inOfs(int offset) {
|
AEADBufferTest inOfs(int offset) {
|
||||||
this.inOfs = offset;
|
this.inOfs = offset;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -211,9 +229,8 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
/**
|
/**
|
||||||
* Set the output offset
|
* Set the output offset
|
||||||
* @param offset value for output offset
|
* @param offset value for output offset
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
GCMBufferTest outOfs(int offset) {
|
AEADBufferTest outOfs(int offset) {
|
||||||
this.outOfs = offset;
|
this.outOfs = offset;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -340,6 +357,15 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AlgorithmParameterSpec getAPS(String algo, int tLen, byte[] iv) {
|
||||||
|
return switch (algo) {
|
||||||
|
case "AES", "AES/GCM/NoPadding" ->
|
||||||
|
new GCMParameterSpec(tLen * 8, iv);
|
||||||
|
case "CC20", "ChaCha20-Poly1305" -> new IvParameterSpec(iv);
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform cipher operation using different input and output buffers.
|
* Perform cipher operation using different input and output buffers.
|
||||||
* This method allows mixing of data types (byte, heap, direct).
|
* This method allows mixing of data types (byte, heap, direct).
|
||||||
@ -355,11 +381,11 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
int dataoffset = 0; // offset of unconsumed data in pt
|
int dataoffset = 0; // offset of unconsumed data in pt
|
||||||
int index = 0; // index of which op we are on
|
int index = 0; // index of which op we are on
|
||||||
int rlen; // result length
|
int rlen; // result length
|
||||||
int pbuflen = 0; // plen remaining in the GCM internal buffers
|
int pbuflen = 0; // plen remaining in the internal buffers
|
||||||
|
|
||||||
Cipher cipher = Cipher.getInstance(algo);
|
Cipher cipher = Cipher.getInstance(algo);
|
||||||
cipher.init((encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE),
|
cipher.init((encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE),
|
||||||
d.key, new GCMParameterSpec(d.tag.length * 8, d.iv));
|
d.key, getAPS(algo, d.tag.length, d.iv));
|
||||||
cipher.updateAAD(d.aad);
|
cipher.updateAAD(d.aad);
|
||||||
|
|
||||||
ByteArrayOutputStream ba = new ByteArrayOutputStream();
|
ByteArrayOutputStream ba = new ByteArrayOutputStream();
|
||||||
@ -382,10 +408,11 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The theoretical limit is the length of the data sent to
|
* The theoretical limit is the length of the data sent to
|
||||||
* update() + any data might be setting in CipherCore or GCM
|
* update() + any data might be setting in CipherCore or AEAD
|
||||||
* internal buffers % the block size.
|
* internal buffers % the block size.
|
||||||
*/
|
*/
|
||||||
theoreticallen = (plen + pbuflen) - ((plen + pbuflen) % AESBLOCK);
|
theoreticallen = (plen + pbuflen) - (d.blockSize > 0 ?
|
||||||
|
(plen + pbuflen) % d.blockSize : 0);
|
||||||
|
|
||||||
// Update operations
|
// Update operations
|
||||||
switch (v) {
|
switch (v) {
|
||||||
@ -525,7 +552,8 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
byte[] expectedOut = new byte[output.length + outOfs];
|
byte[] expectedOut = new byte[output.length + outOfs];
|
||||||
System.arraycopy(output, 0, expectedOut, outOfs, output.length);
|
System.arraycopy(output, 0, expectedOut, outOfs, output.length);
|
||||||
int plen = input.length / ops.size(); // partial input length
|
int plen = input.length / ops.size(); // partial input length
|
||||||
int theorticallen = plen - (plen % AESBLOCK); // output length
|
int theorticallen = plen -
|
||||||
|
(d.blockSize > 0 ? plen % d.blockSize : 0); // output length
|
||||||
int dataoffset = 0;
|
int dataoffset = 0;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int rlen = 0; // result length
|
int rlen = 0; // result length
|
||||||
@ -533,7 +561,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
|
|
||||||
Cipher cipher = Cipher.getInstance(algo);
|
Cipher cipher = Cipher.getInstance(algo);
|
||||||
cipher.init((encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE),
|
cipher.init((encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE),
|
||||||
d.key, new GCMParameterSpec(d.tag.length * 8, d.iv));
|
d.key, getAPS(algo, d.tag.length, d.iv));
|
||||||
cipher.updateAAD(d.aad);
|
cipher.updateAAD(d.aad);
|
||||||
|
|
||||||
// Prepare data
|
// Prepare data
|
||||||
@ -567,8 +595,8 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
data, len + outOfs);
|
data, len + outOfs);
|
||||||
}
|
}
|
||||||
case HEAP, DIRECT -> {
|
case HEAP, DIRECT -> {
|
||||||
theorticallen = bbin.remaining() -
|
theorticallen = bbin.remaining() - (d.blockSize > 0 ?
|
||||||
(bbin.remaining() % AESBLOCK);
|
bbin.remaining() % d.blockSize : 0);
|
||||||
rlen = cipher.update(bbin, bbout);
|
rlen = cipher.update(bbin, bbout);
|
||||||
}
|
}
|
||||||
default -> throw new Exception("Unknown op: " + v.name());
|
default -> throw new Exception("Unknown op: " + v.name());
|
||||||
@ -620,7 +648,7 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void offsetTests(GCMBufferTest t) throws Exception {
|
static void offsetTests(AEADBufferTest t) throws Exception {
|
||||||
t.clone().offset(2).test();
|
t.clone().offset(2).test();
|
||||||
t.clone().inOfs(2).test();
|
t.clone().inOfs(2).test();
|
||||||
// Test not designed for overlap situations
|
// Test not designed for overlap situations
|
||||||
@ -628,108 +656,205 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) throws Exception {
|
public static void main(String args[]) throws Exception {
|
||||||
GCMBufferTest t;
|
AEADBufferTest t;
|
||||||
|
|
||||||
initTest();
|
initTest();
|
||||||
|
|
||||||
|
// **** GCM Tests
|
||||||
|
|
||||||
// Test single byte array
|
// Test single byte array
|
||||||
new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE)).test();
|
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE)));
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE)));
|
||||||
// Test update-doFinal with byte arrays
|
// Test update-doFinal with byte arrays
|
||||||
new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE)).test();
|
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE)));
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE)));
|
||||||
// Test update-update-doFinal with byte arrays
|
// Test update-update-doFinal with byte arrays
|
||||||
new GCMBufferTest("AES/GCM/NoPadding",
|
new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).test();
|
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)));
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)));
|
||||||
|
|
||||||
// Test single heap bytebuffer
|
// Test single heap bytebuffer
|
||||||
new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP)).test();
|
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP)));
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP)));
|
||||||
// Test update-doFinal with heap bytebuffer
|
// Test update-doFinal with heap bytebuffer
|
||||||
new GCMBufferTest("AES/GCM/NoPadding",
|
new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.HEAP, dtype.HEAP)).test();
|
List.of(dtype.HEAP, dtype.HEAP)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP, dtype.HEAP)));
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP, dtype.HEAP)));
|
||||||
// Test update-update-doFinal with heap bytebuffer
|
// Test update-update-doFinal with heap bytebuffer
|
||||||
new GCMBufferTest("AES/GCM/NoPadding",
|
new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)).test();
|
List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)));
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.HEAP, dtype.HEAP, dtype.HEAP)));
|
||||||
|
|
||||||
// Test single direct bytebuffer
|
// Test single direct bytebuffer
|
||||||
new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.DIRECT)).test();
|
new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.DIRECT)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding", List.of(dtype.DIRECT)));
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding", List.of(dtype.DIRECT)));
|
||||||
// Test update-doFinal with direct bytebuffer
|
// Test update-doFinal with direct bytebuffer
|
||||||
new GCMBufferTest("AES/GCM/NoPadding",
|
new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.DIRECT, dtype.DIRECT)).test();
|
List.of(dtype.DIRECT, dtype.DIRECT)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding",
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.DIRECT, dtype.DIRECT)));
|
List.of(dtype.DIRECT, dtype.DIRECT)));
|
||||||
// Test update-update-doFinal with direct bytebuffer
|
// Test update-update-doFinal with direct bytebuffer
|
||||||
new GCMBufferTest("AES/GCM/NoPadding",
|
new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).test();
|
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).test();
|
||||||
offsetTests(new GCMBufferTest("AES/GCM/NoPadding",
|
offsetTests(new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)));
|
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)));
|
||||||
|
|
||||||
// Test update-update-doFinal with byte arrays and preset data sizes
|
// Test update-update-doFinal with byte arrays and preset data sizes
|
||||||
t = new GCMBufferTest("AES/GCM/NoPadding",
|
t = new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).dataSegments(
|
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).dataSegments(
|
||||||
new int[] { 1, 1, GCMBufferTest.REMAINDER});
|
new int[] { 1, 1, AEADBufferTest.REMAINDER});
|
||||||
t.clone().test();
|
t.clone().test();
|
||||||
offsetTests(t.clone());
|
offsetTests(t.clone());
|
||||||
|
|
||||||
// Test update-doFinal with a byte array and a direct bytebuffer
|
// Test update-doFinal with a byte array and a direct bytebuffer
|
||||||
t = new GCMBufferTest("AES/GCM/NoPadding",
|
t = new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.BYTE, dtype.DIRECT)).differentBufferOnly();
|
List.of(dtype.BYTE, dtype.DIRECT)).differentBufferOnly();
|
||||||
t.clone().test();
|
t.clone().test();
|
||||||
offsetTests(t.clone());
|
offsetTests(t.clone());
|
||||||
// Test update-doFinal with a byte array and heap and direct bytebuffer
|
// Test update-doFinal with a byte array and heap and direct bytebuffer
|
||||||
t = new GCMBufferTest("AES/GCM/NoPadding",
|
t = new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.BYTE, dtype.HEAP, dtype.DIRECT)).differentBufferOnly();
|
List.of(dtype.BYTE, dtype.HEAP, dtype.DIRECT)).differentBufferOnly();
|
||||||
t.clone().test();
|
t.clone().test();
|
||||||
offsetTests(t.clone());
|
offsetTests(t.clone());
|
||||||
|
|
||||||
// Test update-doFinal with a direct bytebuffer and a byte array.
|
// Test update-doFinal with a direct bytebuffer and a byte array.
|
||||||
t = new GCMBufferTest("AES/GCM/NoPadding",
|
t = new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly();
|
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly();
|
||||||
t.clone().test();
|
t.clone().test();
|
||||||
offsetTests(t.clone());
|
offsetTests(t.clone());
|
||||||
|
|
||||||
// Test update-doFinal with a direct bytebuffer and a byte array with
|
// Test update-doFinal with a direct bytebuffer and a byte array with
|
||||||
// preset data sizes.
|
// preset data sizes.
|
||||||
t = new GCMBufferTest("AES/GCM/NoPadding",
|
t = new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly().
|
List.of(dtype.DIRECT, dtype.BYTE)).differentBufferOnly().
|
||||||
dataSegments(new int[] { 20, GCMBufferTest.REMAINDER });
|
dataSegments(new int[] { 20, AEADBufferTest.REMAINDER });
|
||||||
t.clone().test();
|
t.clone().test();
|
||||||
offsetTests(t.clone());
|
offsetTests(t.clone());
|
||||||
// Test update-update-doFinal with a direct and heap bytebuffer and a
|
// Test update-update-doFinal with a direct and heap bytebuffer and a
|
||||||
// byte array with preset data sizes.
|
// byte array with preset data sizes.
|
||||||
t = new GCMBufferTest("AES/GCM/NoPadding",
|
t = new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.DIRECT, dtype.BYTE, dtype.HEAP)).
|
List.of(dtype.DIRECT, dtype.BYTE, dtype.HEAP)).
|
||||||
differentBufferOnly().dataSet(5).
|
differentBufferOnly().dataSet(5).
|
||||||
dataSegments(new int[] { 5000, 1000, GCMBufferTest.REMAINDER });
|
dataSegments(new int[] { 5000, 1000, AEADBufferTest.REMAINDER });
|
||||||
t.clone().test();
|
t.clone().test();
|
||||||
offsetTests(t.clone());
|
offsetTests(t.clone());
|
||||||
|
|
||||||
// Test update-update-doFinal with byte arrays, incrementing through
|
// Test update-update-doFinal with byte arrays, incrementing through
|
||||||
// every data size combination for the Data set 0
|
// every data size combination for the Data set 0
|
||||||
new GCMBufferTest("AES/GCM/NoPadding",
|
new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).incrementalSegments().
|
List.of(dtype.BYTE, dtype.BYTE, dtype.BYTE)).incrementalSegments().
|
||||||
dataSet(0).test();
|
dataSet(0).test();
|
||||||
// Test update-update-doFinal with direct bytebuffers, incrementing through
|
// Test update-update-doFinal with direct bytebuffers, incrementing through
|
||||||
// every data size combination for the Data set 0
|
// every data size combination for the Data set 0
|
||||||
new GCMBufferTest("AES/GCM/NoPadding",
|
new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
|
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
|
||||||
incrementalSegments().dataSet(0).test();
|
incrementalSegments().dataSet(0).test();
|
||||||
|
|
||||||
new GCMBufferTest("AES/GCM/NoPadding",
|
new AEADBufferTest("AES/GCM/NoPadding",
|
||||||
|
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
|
||||||
|
dataSegments(new int[] { 49, 0, 2 }).dataSet(0).test();
|
||||||
|
|
||||||
|
// **** CC20P1305 Tests
|
||||||
|
|
||||||
|
// 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 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 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-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 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-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 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)).
|
List.of(dtype.DIRECT, dtype.DIRECT, dtype.DIRECT)).
|
||||||
dataSegments(new int[] { 49, 0, 2 }).dataSet(0).test();
|
dataSegments(new int[] { 49, 0, 2 }).dataSet(0).test();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test data
|
// Test data
|
||||||
static void initTest() {
|
static void initTest() {
|
||||||
|
|
||||||
datamap.put("AES/GCM/NoPadding", List.of(
|
datamap.put("AES/GCM/NoPadding", List.of(
|
||||||
// GCM KAT
|
// GCM KAT
|
||||||
new Data("AES", 0,
|
new Data(AES, 0,
|
||||||
"141f1ce91989b07e7eb6ae1dbd81ea5e",
|
"141f1ce91989b07e7eb6ae1dbd81ea5e",
|
||||||
"49451da24bd6074509d3cebc2c0394c972e6934b45a1d91f3ce1d3ca69e19" +
|
"49451da24bd6074509d3cebc2c0394c972e6934b45a1d91f3ce1d3ca69e19" +
|
||||||
"4aa1958a7c21b6f21d530ce6d2cc5256a3f846b6f9d2f38df0102c4791e5" +
|
"4aa1958a7c21b6f21d530ce6d2cc5256a3f846b6f9d2f38df0102c4791e5" +
|
||||||
@ -744,100 +869,32 @@ public class GCMBufferTest implements Cloneable {
|
|||||||
"240446b28dc088abd42b0fc687f208190ff24c0548",
|
"240446b28dc088abd42b0fc687f208190ff24c0548",
|
||||||
"dbb93bbb56d0439cd09f620a57687f5d"),
|
"dbb93bbb56d0439cd09f620a57687f5d"),
|
||||||
// GCM KAT
|
// GCM KAT
|
||||||
new Data("AES", 1, "11754cd72aec309bf52f7687212e8957",
|
new Data(AES, 1, "11754cd72aec309bf52f7687212e8957",
|
||||||
"3c819d9a9bed087615030b65",
|
"3c819d9a9bed087615030b65",
|
||||||
(String)null, null, null,
|
new byte[0], null, null,
|
||||||
"250327c674aaf477aef2675748cf6971"),
|
"250327c674aaf477aef2675748cf6971"),
|
||||||
// GCM KAT
|
|
||||||
new Data("AES", 2, "272f16edb81a7abbea887357a58c1917",
|
|
||||||
"794ec588176c703d3d2a7a07",
|
|
||||||
(String)null, null, null,
|
|
||||||
"b6e6f197168f5049aeda32dafbdaeb"),
|
|
||||||
// zero'd test data
|
|
||||||
new Data("AES", 3, "272f16edb81a7abbea887357a58c1917",
|
|
||||||
"794ec588176c703d3d2a7a07", new byte[256], null,
|
|
||||||
"15b461672153270e8ba1e6789f7641c5411f3e642abda731b6086f535c216457" +
|
|
||||||
"e87305bc59a1ff1f7e1e0bbdf302b75549b136606c67d7e5f71277aeca4bc670" +
|
|
||||||
"07a98f78e0cfa002ed183e62f07893ad31fe67aad1bb37e15b957a14d145f14f" +
|
|
||||||
"7483d041f2c3612ad5033155984470bdfc64d18df73c2745d92f28461bb09832" +
|
|
||||||
"33524811321ba87d213692825815dd13f528dba601a3c319cac6be9b48686c23" +
|
|
||||||
"a0ce23d5062916ea8827bbb243f585e446131489e951354c8ab24661f625c02e" +
|
|
||||||
"15536c5bb602244e98993ff745f3e523399b2059f0e062d8933fad2366e7e147" +
|
|
||||||
"510a931282bb0e3f635efe7bf05b1dd715f95f5858261b00735224256b6b3e80",
|
|
||||||
"08b3593840d4ed005f5234ae062a5c"),
|
|
||||||
// Random test data
|
|
||||||
new Data("AES", 4, "272f16edb81a7abbea887357a58c1917",
|
|
||||||
"794ec588176c703d3d2a7a07",
|
|
||||||
new byte[2075], null,
|
|
||||||
"15b461672153270e8ba1e6789f7641c5411f3e642abda731b6086f535c216457" +
|
|
||||||
"e87305bc59a1ff1f7e1e0bbdf302b75549b136606c67d7e5f71277aeca4bc670" +
|
|
||||||
"07a98f78e0cfa002ed183e62f07893ad31fe67aad1bb37e15b957a14d145f14f" +
|
|
||||||
"7483d041f2c3612ad5033155984470bdfc64d18df73c2745d92f28461bb09832" +
|
|
||||||
"33524811321ba87d213692825815dd13f528dba601a3c319cac6be9b48686c23" +
|
|
||||||
"a0ce23d5062916ea8827bbb243f585e446131489e951354c8ab24661f625c02e" +
|
|
||||||
"15536c5bb602244e98993ff745f3e523399b2059f0e062d8933fad2366e7e147" +
|
|
||||||
"510a931282bb0e3f635efe7bf05b1dd715f95f5858261b00735224256b6b3e80" +
|
|
||||||
"7364cb53ff6d4e88f928cf67ac70da127718a8a35542efbae9dd7567c818a074" +
|
|
||||||
"9a0c74bd69014639f59768bc55056d1166ea5523e8c66f9d78d980beb8f0d83b" +
|
|
||||||
"a9e2c5544b94dc3a1a4b6f0f95f897b010150e89ebcacf0daee3c2793d6501a0" +
|
|
||||||
"b58b411de273dee987e8e8cf8bb29ef2e7f655b46b55fabf64c6a4295e0d080b" +
|
|
||||||
"6a570ace90eb0fe0f5b5d878bdd90eddaa1150e4d5a6505b350aac814fe99615" +
|
|
||||||
"317ecd0516a464c7904011ef5922409c0d65b1e43b69d7c3293a8f7d3e9fbee9" +
|
|
||||||
"eb91ec0007a7d6f72e64deb675d459c5ba07dcfd58d08e6820b100465e6e04f0" +
|
|
||||||
"663e310584a00d36d23699c1bffc6afa094c75184fc7cde7ad35909c0f49f2f3" +
|
|
||||||
"fe1e6d745ab628d74ea56b757047de57ce18b4b3c71e8af31a6fac16189cb0a3" +
|
|
||||||
"a97a1bea447042ce382fcf726560476d759c24d5c735525ea26a332c2094408e" +
|
|
||||||
"671c7deb81d5505bbfd178f866a6f3a011b3cfdbe089b4957a790688028dfdf7" +
|
|
||||||
"9a096b3853f9d0d6d3feef230c7f5f46ffbf7486ebdaca5804dc5bf9d202415e" +
|
|
||||||
"e0d67b365c2f92a17ea740807e4f0b198b42b54f15faa9dff2c7c35d2cf8d72e" +
|
|
||||||
"b8f8b18875a2e7b5c43d1e0aa5139c461e8153c7f632895aa46ffe2b134e6a0d" +
|
|
||||||
"dfbf6a336e709adfe951bd52c4dfc7b07a15fb3888fc35b7e758922f87a104c4" +
|
|
||||||
"563c5c7839cfe5a7edbdb97264a7c4ebc90367b10cbe09dbf2390767ad7afaa8" +
|
|
||||||
"8fb46b39d3f55f216d2104e5cf040bf3d39b758bea28e2dbce576c808d17a8eb" +
|
|
||||||
"e2fd183ef42a774e39119dff1f539efeb6ad15d889dfcb0d54d0d4d4cc03c8d9" +
|
|
||||||
"aa6c9ebd157f5e7170183298d6a30ada8792dcf793d931e2a1eafccbc63c11c0" +
|
|
||||||
"c5c5ed60837f30017d693ccb294df392a8066a0594a56954aea7b78a16e9a11f" +
|
|
||||||
"4a8bc2104070a7319f5fab0d2c4ccad8ec5cd8f47c839179bfd54a7bf225d502" +
|
|
||||||
"cd0a318752fe763e8c09eb88fa57fc5399ad1f797d0595c7b8afdd23f13603e9" +
|
|
||||||
"6802192bb51433b7723f4e512bd4f799feb94b458e7f9792f5f9bd6733828f70" +
|
|
||||||
"a6b7ffbbc0bb7575021f081ec2a0d37fecd7cda2daec9a3a9d9dfe1c8034cead" +
|
|
||||||
"e4b56b581cc82bd5b74b2b30817967d9da33850336f171a4c68e2438e03f4b11" +
|
|
||||||
"96da92f01b3b7aeab795180ccf40a4b090b1175a1fc0b67c95f93105c3aef00e" +
|
|
||||||
"13d76cc402539192274fee703730cd0d1c5635257719cc96cacdbad00c6255e2" +
|
|
||||||
"bd40c775b43ad09599e84f2c3205d75a6661ca3f151183be284b354ce21457d1" +
|
|
||||||
"3ba65b9b2cdb81874bd14469c2008b3ddec78f7225ecc710cc70de7912ca6a6d" +
|
|
||||||
"348168322ab59fdafcf5c833bfa0ad4046f4b6da90e9f263db7079af592eda07" +
|
|
||||||
"5bf16c6b1a8346da9c292a48bf660860a4fc89eaef40bc132779938eca294569" +
|
|
||||||
"787c740af2b5a8de7f5e10ac750d1e3d0ef3ed168ba408a676e10b8a20bd4be8" +
|
|
||||||
"3e8336b45e54481726d73e1bd19f165a98e242aca0d8387f2dd22d02d74e23db" +
|
|
||||||
"4cef9a523587413e0a44d7e3260019a34d3a6b38426ae9fa4655be338d721970" +
|
|
||||||
"cb9fe76c073f26f9303093a033022cd2c62b2790bce633ba9026a1c93b6535f1" +
|
|
||||||
"1882bf5880e511b9e1b0b7d8f23a993aae5fd275faac3a5b4ccaf7c06b0b266a" +
|
|
||||||
"ee970a1e3a4cd7a41094f516960630534e692545b25a347c30e3f328bba4825f" +
|
|
||||||
"ed754e5525d846131ecba7ca120a6aeabc7bab9f59c890c80b7e31f9bc741591" +
|
|
||||||
"55d292433ce9558e104102f2cc63ee267c1c8333e841522707ea6d595cb802b9" +
|
|
||||||
"61697da77bbc4cb404ea62570ab335ebffa2023730732ac5ddba1c3dbb5be408" +
|
|
||||||
"3c50aea462c1ffa166d7cc3db4b742b747e81b452db2363e91374dee8c6b40f0" +
|
|
||||||
"e7fbf50e60eaf5cc5649f6bb553aae772c185026ceb052af088c545330a1ffbf" +
|
|
||||||
"50615b8c7247c6cd386afd7440654f4e15bcfae0c45442ec814fe88433a9d616" +
|
|
||||||
"ee6cc3f163f0d3d325526d05f25d3b37ad5eeb3ca77248ad86c9042b16c65554" +
|
|
||||||
"aebb6ad3e17b981492b13f42c5a5dc088e991da303e5a273fdbb8601aece4267" +
|
|
||||||
"47b01f6cb972e6da1743a0d7866cf206e95f23c6f8e337c901b9cd34a9a1fbbe" +
|
|
||||||
"1694f2c26b00dfa4d02c0d54540163e798fbdc9c25f30d6406f5b4c13f7ed619" +
|
|
||||||
"34e350f4059c13aa5e973307a9e3058917cda96fdd082e9c629ccfb2a9f98d12" +
|
|
||||||
"5c6e4703a7b0f348f5cdeb63cef2133d1c6c1a087591e0a2bca29d09c6565e66" +
|
|
||||||
"e91042f83b0e74e60a5d57562c23e2fbcd6599c29d7c19e47cf625c2ce24bb8a" +
|
|
||||||
"13f8e54041498437eec2cedd1e3d8e57a051baa962c0a62d70264d99c5ee716d" +
|
|
||||||
"5c8b9078db08c8b2c5613f464198a7aff43f76c5b4612b46a4f1cd2a494386c5" +
|
|
||||||
"7fd28f3d199f0ba8d8e39116cc7db16ce6188205ee49a9dce3d4fa32ea394919" +
|
|
||||||
"f6e91ef58b84d00b99596b4306c2d9f432d917bb4ac73384c42ae12adb4920d8" +
|
|
||||||
"c33a816febcb299dcddf3ec7a8eb6e04cdc90891c6e145bd9fc5f41dc4061a46" +
|
|
||||||
"9feba38545b64ec8203f386ceef52785619e991d274ae80af7e54af535e0b011" +
|
|
||||||
"5effdf847472992875e09398457604d04e0bb965db692c0cdcf11a",
|
|
||||||
"687cc09c89298491deb51061d709af"),
|
|
||||||
// Randomly generated data at the time of execution.
|
// Randomly generated data at the time of execution.
|
||||||
new Data("AES", 5, "11754cd72aec309bf52f7687212e8957", 12345)
|
new Data(AES, 5, "11754cd72aec309bf52f7687212e8957",
|
||||||
)
|
16, 12345)));
|
||||||
);
|
|
||||||
|
datamap.put("ChaCha20-Poly1305", List.of(
|
||||||
|
new Data("CC20", 0,
|
||||||
|
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
|
||||||
|
"070000004041424344454647",
|
||||||
|
1,
|
||||||
|
"4c616469657320616e642047656e746c656d656e206f662074686520636c6173" +
|
||||||
|
"73206f66202739393a204966204920636f756c64206f6666657220796f75206f" +
|
||||||
|
"6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73" +
|
||||||
|
"637265656e20776f756c642062652069742e",
|
||||||
|
"50515253c0c1c2c3c4c5c6c7",
|
||||||
|
"d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d6" +
|
||||||
|
"3dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b36" +
|
||||||
|
"92ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc" +
|
||||||
|
"3ff4def08e4b7a9de576d26586cec64b61161ae10b59",
|
||||||
|
"4f09e26a7e902ecbd0600691"),
|
||||||
|
// Randomly generated data at the time of execution.
|
||||||
|
new Data("CC20", 1,
|
||||||
|
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
|
||||||
|
12, 12345)));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -22,107 +22,31 @@
|
|||||||
*/
|
*/
|
||||||
package org.openjdk.bench.javax.crypto.full;
|
package org.openjdk.bench.javax.crypto.full;
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
|
||||||
import org.openjdk.jmh.annotations.Param;
|
import org.openjdk.jmh.annotations.Param;
|
||||||
import org.openjdk.jmh.annotations.Setup;
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
import javax.crypto.spec.GCMParameterSpec;
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This performance tests runs AES/GCM encryption and decryption using byte[]
|
* This performance tests runs AES/GCM encryption and decryption
|
||||||
* as input and output buffers for single and multi-part testing.
|
* using input and output byte[] buffers with single and multi-part testing.
|
||||||
*
|
|
||||||
* This test rotates the IV and creates a new GCMParameterSpec for each encrypt
|
|
||||||
* benchmark operation
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AESGCMBench extends CryptoBase {
|
public class AESGCMBench extends BenchBase {
|
||||||
|
|
||||||
@Param({"128"})
|
@Param({"128"})
|
||||||
private int keyLength;
|
int keyLength;
|
||||||
|
|
||||||
@Param({"1024", "1500", "4096", "16384"})
|
public static final int IV_MODULO = 16;
|
||||||
private int dataSize;
|
|
||||||
|
|
||||||
byte[] encryptedData;
|
public AlgorithmParameterSpec getNewSpec() {
|
||||||
byte[] in, out;
|
|
||||||
private Cipher encryptCipher;
|
|
||||||
private Cipher decryptCipher;
|
|
||||||
SecretKeySpec ks;
|
|
||||||
GCMParameterSpec gcm_spec;
|
|
||||||
byte[] iv;
|
|
||||||
|
|
||||||
private static final int IV_BUFFER_SIZE = 32;
|
|
||||||
private static final int IV_MODULO = IV_BUFFER_SIZE - 16;
|
|
||||||
int iv_index = 0;
|
|
||||||
int updateLen = 0;
|
|
||||||
|
|
||||||
private int next_iv_index() {
|
|
||||||
int r = iv_index;
|
|
||||||
iv_index = (iv_index + 1) % IV_MODULO;
|
iv_index = (iv_index + 1) % IV_MODULO;
|
||||||
return r;
|
return new GCMParameterSpec(128, iv, iv_index, IV_MODULO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Setup
|
@Setup
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
setupProvider();
|
init("AES/GCM/NoPadding", keyLength);
|
||||||
|
|
||||||
// Setup key material
|
|
||||||
byte[] keystring = fillSecureRandom(new byte[keyLength / 8]);
|
|
||||||
ks = new SecretKeySpec(keystring, "AES");
|
|
||||||
iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]);
|
|
||||||
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
|
|
||||||
|
|
||||||
// Setup Cipher classes
|
|
||||||
encryptCipher = makeCipher(prov, "AES/GCM/NoPadding");
|
|
||||||
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
|
|
||||||
decryptCipher = makeCipher(prov, "AES/GCM/NoPadding");
|
|
||||||
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
|
|
||||||
encryptCipher.getParameters().
|
|
||||||
getParameterSpec(GCMParameterSpec.class));
|
|
||||||
|
|
||||||
// Setup input/output buffers
|
|
||||||
in = fillRandom(new byte[dataSize]);
|
|
||||||
encryptedData = new byte[encryptCipher.getOutputSize(in.length)];
|
|
||||||
out = new byte[encryptedData.length];
|
|
||||||
encryptCipher.doFinal(in, 0, in.length, encryptedData, 0);
|
|
||||||
updateLen = in.length / 2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void encrypt() throws Exception {
|
|
||||||
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
|
|
||||||
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
|
|
||||||
encryptCipher.doFinal(in, 0, in.length, out, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void encryptMultiPart() throws Exception {
|
|
||||||
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
|
|
||||||
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
|
|
||||||
int outOfs = encryptCipher.update(in, 0, updateLen, out, 0);
|
|
||||||
encryptCipher.doFinal(in, updateLen, in.length - updateLen,
|
|
||||||
out, outOfs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void decrypt() throws Exception {
|
|
||||||
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
|
|
||||||
encryptCipher.getParameters().
|
|
||||||
getParameterSpec(GCMParameterSpec.class));
|
|
||||||
decryptCipher.doFinal(encryptedData, 0, encryptedData.length, out, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void decryptMultiPart() throws Exception {
|
|
||||||
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
|
|
||||||
encryptCipher.getParameters().
|
|
||||||
getParameterSpec(GCMParameterSpec.class));
|
|
||||||
decryptCipher.update(encryptedData, 0, updateLen, out, 0);
|
|
||||||
decryptCipher.doFinal(encryptedData, updateLen,
|
|
||||||
encryptedData.length - updateLen, out, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -22,140 +22,32 @@
|
|||||||
*/
|
*/
|
||||||
package org.openjdk.bench.javax.crypto.full;
|
package org.openjdk.bench.javax.crypto.full;
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
|
||||||
import org.openjdk.jmh.annotations.Param;
|
import org.openjdk.jmh.annotations.Param;
|
||||||
import org.openjdk.jmh.annotations.Setup;
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
import javax.crypto.spec.GCMParameterSpec;
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This performance tests runs AES/GCM encryption and decryption using heap and
|
* This performance tests runs AES/GCM encryption and decryption using heap and
|
||||||
* direct ByteBuffers as input and output buffers for single and multi-part
|
* direct ByteBuffers as input and output buffers for single and multi-part
|
||||||
* operations.
|
* operations.
|
||||||
*
|
|
||||||
* This test rotates the IV and creates a new GCMParameterSpec for each encrypt
|
|
||||||
* benchmark operation
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AESGCMByteBuffer extends CryptoBase {
|
public class AESGCMByteBuffer extends ByteBufferBase {
|
||||||
|
|
||||||
@Param({"128"})
|
@Param({"128"})
|
||||||
private int keyLength;
|
int keyLength;
|
||||||
|
|
||||||
@Param({"1024", "1500", "4096", "16384"})
|
public static final int IV_MODULO = 16;
|
||||||
private int dataSize;
|
|
||||||
|
|
||||||
@Param({"direct", "heap"})
|
public AlgorithmParameterSpec getNewSpec() {
|
||||||
private String dataMethod;
|
|
||||||
|
|
||||||
byte[] data;
|
|
||||||
ByteBuffer encryptedData;
|
|
||||||
ByteBuffer in, out;
|
|
||||||
private Cipher encryptCipher;
|
|
||||||
private Cipher decryptCipher;
|
|
||||||
SecretKeySpec ks;
|
|
||||||
GCMParameterSpec gcm_spec;
|
|
||||||
byte[] iv;
|
|
||||||
|
|
||||||
private static final int IV_BUFFER_SIZE = 32;
|
|
||||||
private static final int IV_MODULO = IV_BUFFER_SIZE - 16;
|
|
||||||
int iv_index = 0;
|
|
||||||
int updateLen = 0;
|
|
||||||
|
|
||||||
private int next_iv_index() {
|
|
||||||
int r = iv_index;
|
|
||||||
iv_index = (iv_index + 1) % IV_MODULO;
|
iv_index = (iv_index + 1) % IV_MODULO;
|
||||||
return r;
|
return new GCMParameterSpec(128, iv, iv_index, IV_MODULO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Setup
|
@Setup
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
setupProvider();
|
init("AES/GCM/NoPadding", keyLength);
|
||||||
|
|
||||||
// Setup key material
|
|
||||||
byte[] keystring = fillSecureRandom(new byte[keyLength / 8]);
|
|
||||||
ks = new SecretKeySpec(keystring, "AES");
|
|
||||||
iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]);
|
|
||||||
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
|
|
||||||
|
|
||||||
// Setup Cipher classes
|
|
||||||
encryptCipher = makeCipher(prov, "AES/GCM/NoPadding");
|
|
||||||
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
|
|
||||||
decryptCipher = makeCipher(prov, "AES/GCM/NoPadding");
|
|
||||||
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
|
|
||||||
encryptCipher.getParameters().
|
|
||||||
getParameterSpec(GCMParameterSpec.class));
|
|
||||||
|
|
||||||
// Setup input/output buffers
|
|
||||||
data = fillRandom(new byte[dataSize]);
|
|
||||||
if (dataMethod.equalsIgnoreCase("direct")) {
|
|
||||||
in = ByteBuffer.allocateDirect(data.length);
|
|
||||||
in.put(data);
|
|
||||||
in.flip();
|
|
||||||
encryptedData = ByteBuffer.allocateDirect(
|
|
||||||
encryptCipher.getOutputSize(data.length));
|
|
||||||
out = ByteBuffer.allocateDirect(encryptedData.capacity());
|
|
||||||
} else if (dataMethod.equalsIgnoreCase("heap")) {
|
|
||||||
in = ByteBuffer.wrap(data);
|
|
||||||
encryptedData = ByteBuffer.allocate(
|
|
||||||
encryptCipher.getOutputSize(data.length));
|
|
||||||
out = ByteBuffer.allocate(encryptedData.capacity());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptCipher.doFinal(in, encryptedData);
|
|
||||||
encryptedData.flip();
|
|
||||||
in.flip();
|
|
||||||
updateLen = in.remaining() / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void encrypt() throws Exception {
|
|
||||||
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
|
|
||||||
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
|
|
||||||
encryptCipher.doFinal(in, out);
|
|
||||||
out.flip();
|
|
||||||
in.flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void encryptMultiPart() throws Exception {
|
|
||||||
gcm_spec = new GCMParameterSpec(96, iv, next_iv_index(), 16);
|
|
||||||
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, gcm_spec);
|
|
||||||
in.limit(updateLen);
|
|
||||||
encryptCipher.update(in, out);
|
|
||||||
in.limit(in.capacity());
|
|
||||||
encryptCipher.doFinal(in, out);
|
|
||||||
out.flip();
|
|
||||||
in.flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void decrypt() throws Exception {
|
|
||||||
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
|
|
||||||
encryptCipher.getParameters().
|
|
||||||
getParameterSpec(GCMParameterSpec.class));
|
|
||||||
decryptCipher.doFinal(encryptedData, out);
|
|
||||||
encryptedData.flip();
|
|
||||||
out.flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void decryptMultiPart() throws Exception {
|
|
||||||
decryptCipher.init(Cipher.DECRYPT_MODE, ks,
|
|
||||||
encryptCipher.getParameters().
|
|
||||||
getParameterSpec(GCMParameterSpec.class));
|
|
||||||
|
|
||||||
int len = encryptedData.remaining();
|
|
||||||
encryptedData.limit(updateLen);
|
|
||||||
decryptCipher.update(encryptedData, out);
|
|
||||||
encryptedData.limit(len);
|
|
||||||
|
|
||||||
decryptCipher.doFinal(encryptedData, out);
|
|
||||||
encryptedData.flip();
|
|
||||||
out.flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
131
test/micro/org/openjdk/bench/javax/crypto/full/BenchBase.java
Normal file
131
test/micro/org/openjdk/bench/javax/crypto/full/BenchBase.java
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.javax.crypto.full;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the common code for the AES/GCM and ChaCha20-Poly1305 performance
|
||||||
|
* tests. Encryption and decryption use byte[] as input and output buffers for
|
||||||
|
* single and multi-part testing.
|
||||||
|
*
|
||||||
|
* The IV rotates through a set buffer and creates a new AlgorithmParameterSpec
|
||||||
|
* for each encrypt benchmark operation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class BenchBase extends CryptoBase {
|
||||||
|
// Defined by the test
|
||||||
|
String algorithm;
|
||||||
|
int keyLength = 256;
|
||||||
|
|
||||||
|
// Default data sizes for full tests
|
||||||
|
@Param({"1024", "1500", "4096", "16384"})
|
||||||
|
int dataSize;
|
||||||
|
|
||||||
|
static final int IV_BUFFER_SIZE = 36;
|
||||||
|
public byte[] iv;
|
||||||
|
public int iv_index = 0;
|
||||||
|
private int updateLen = 0;
|
||||||
|
|
||||||
|
private Cipher encryptCipher, decryptCipher;
|
||||||
|
private byte[] encryptedData, in, out;
|
||||||
|
private SecretKeySpec ks;
|
||||||
|
// Used for decryption to avoid repeated getParameter() calls
|
||||||
|
private AlgorithmParameterSpec spec;
|
||||||
|
|
||||||
|
abstract AlgorithmParameterSpec getNewSpec();
|
||||||
|
|
||||||
|
// Configure setup with particular test parameters
|
||||||
|
public void init(String algorithm, int keyLength) throws Exception {
|
||||||
|
this.algorithm = algorithm;
|
||||||
|
this.keyLength = keyLength;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure setup with particular test parameters
|
||||||
|
public void init(String algorithm, int keyLength, int dataSize)
|
||||||
|
throws Exception {
|
||||||
|
this.dataSize = dataSize;
|
||||||
|
init(algorithm, keyLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initalize test setup
|
||||||
|
private void init() throws Exception {
|
||||||
|
setupProvider();
|
||||||
|
|
||||||
|
// Setup key material
|
||||||
|
iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]);
|
||||||
|
spec = getNewSpec();
|
||||||
|
// CC20 doesn't care about the algorithm name on the key, but AES does.
|
||||||
|
ks = new SecretKeySpec(fillSecureRandom(new byte[keyLength / 8]),
|
||||||
|
"AES");
|
||||||
|
|
||||||
|
// Setup Cipher classes
|
||||||
|
encryptCipher = makeCipher(prov, algorithm);
|
||||||
|
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, spec);
|
||||||
|
decryptCipher = makeCipher(prov, algorithm);
|
||||||
|
decryptCipher.init(Cipher.DECRYPT_MODE, ks, spec);
|
||||||
|
|
||||||
|
// Setup input/output buffers
|
||||||
|
in = fillRandom(new byte[dataSize]);
|
||||||
|
encryptedData = new byte[encryptCipher.getOutputSize(in.length)];
|
||||||
|
out = new byte[encryptedData.length];
|
||||||
|
encryptCipher.doFinal(in, 0, in.length, encryptedData, 0);
|
||||||
|
updateLen = in.length / 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void encrypt() throws Exception {
|
||||||
|
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, getNewSpec());
|
||||||
|
encryptCipher.doFinal(in, 0, in.length, out, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void encryptMultiPart() throws Exception {
|
||||||
|
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, getNewSpec());
|
||||||
|
int outOfs = encryptCipher.update(in, 0, updateLen, out, 0);
|
||||||
|
encryptCipher.doFinal(in, updateLen, in.length - updateLen,
|
||||||
|
out, outOfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void decrypt() throws Exception {
|
||||||
|
decryptCipher.init(Cipher.DECRYPT_MODE, ks, spec);
|
||||||
|
decryptCipher.doFinal(encryptedData, 0, encryptedData.length, out, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void decryptMultiPart() throws Exception {
|
||||||
|
decryptCipher.init(Cipher.DECRYPT_MODE, ks, spec);
|
||||||
|
decryptCipher.update(encryptedData, 0, updateLen, out, 0);
|
||||||
|
decryptCipher.doFinal(encryptedData, updateLen,
|
||||||
|
encryptedData.length - updateLen, out, 0);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.javax.crypto.full;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the common code for the AES/GCM and ChaCha20-Poly1305 performance
|
||||||
|
* tests. Encryption and decryption are run with input and output
|
||||||
|
* ByteBuffers, direct and heap, for single and multi-part testing.
|
||||||
|
*
|
||||||
|
* The IV rotates through a set buffer and creates a new AlgorithmParameterSpec
|
||||||
|
* for each encrypt benchmark operation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class ByteBufferBase extends CryptoBase {
|
||||||
|
// Defined by the test
|
||||||
|
String algorithm;
|
||||||
|
int keyLength = 256;
|
||||||
|
|
||||||
|
@Param({"1024", "1500", "4096", "16384"})
|
||||||
|
int dataSize;
|
||||||
|
|
||||||
|
@Param({"direct", "heap"})
|
||||||
|
String dataMethod;
|
||||||
|
|
||||||
|
static final int IV_BUFFER_SIZE = 36;
|
||||||
|
public byte[] iv;
|
||||||
|
public int iv_index = 0;
|
||||||
|
private int updateLen = 0;
|
||||||
|
|
||||||
|
private Cipher encryptCipher, decryptCipher;
|
||||||
|
private ByteBuffer encryptedData, in, out;
|
||||||
|
private SecretKeySpec ks;
|
||||||
|
// Used for decryption to avoid repeated getParameter() calls
|
||||||
|
private AlgorithmParameterSpec spec;
|
||||||
|
|
||||||
|
abstract AlgorithmParameterSpec getNewSpec();
|
||||||
|
|
||||||
|
// Configure setup with particular test parameters
|
||||||
|
public void init(String algorithm, int keyLength) throws Exception {
|
||||||
|
this.algorithm = algorithm;
|
||||||
|
this.keyLength = keyLength;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure setup with particular test parameters
|
||||||
|
public void init(String algorithm, int keyLength, int dataSize)
|
||||||
|
throws Exception {
|
||||||
|
this.dataSize = dataSize;
|
||||||
|
init(algorithm, keyLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initalize test setup
|
||||||
|
private void init() throws Exception {
|
||||||
|
setupProvider();
|
||||||
|
|
||||||
|
// Setup key material
|
||||||
|
iv = fillSecureRandom(new byte[IV_BUFFER_SIZE]);
|
||||||
|
spec = getNewSpec();
|
||||||
|
// CC20 doesn't care about the algorithm name on the key, but AES does.
|
||||||
|
ks = new SecretKeySpec(fillSecureRandom(new byte[keyLength / 8]),
|
||||||
|
"AES");
|
||||||
|
|
||||||
|
// Setup Cipher classes
|
||||||
|
encryptCipher = makeCipher(prov, algorithm);
|
||||||
|
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, spec);
|
||||||
|
decryptCipher = makeCipher(prov, algorithm);
|
||||||
|
decryptCipher.init(Cipher.DECRYPT_MODE, ks, spec);
|
||||||
|
|
||||||
|
// Setup input/output buffers
|
||||||
|
byte[] data = fillRandom(new byte[dataSize]);
|
||||||
|
if (dataMethod.equalsIgnoreCase("direct")) {
|
||||||
|
in = ByteBuffer.allocateDirect(data.length);
|
||||||
|
in.put(data);
|
||||||
|
in.flip();
|
||||||
|
encryptedData = ByteBuffer.allocateDirect(
|
||||||
|
encryptCipher.getOutputSize(data.length));
|
||||||
|
out = ByteBuffer.allocateDirect(encryptedData.capacity());
|
||||||
|
} else if (dataMethod.equalsIgnoreCase("heap")) {
|
||||||
|
in = ByteBuffer.wrap(data);
|
||||||
|
encryptedData = ByteBuffer.allocate(
|
||||||
|
encryptCipher.getOutputSize(data.length));
|
||||||
|
out = ByteBuffer.allocate(encryptedData.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptCipher.doFinal(in, encryptedData);
|
||||||
|
encryptedData.flip();
|
||||||
|
in.flip();
|
||||||
|
updateLen = in.remaining() / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void encrypt() throws Exception {
|
||||||
|
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, getNewSpec());
|
||||||
|
encryptCipher.doFinal(in, out);
|
||||||
|
out.flip();
|
||||||
|
in.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void encryptMultiPart() throws Exception {
|
||||||
|
encryptCipher.init(Cipher.ENCRYPT_MODE, ks, getNewSpec());
|
||||||
|
in.limit(updateLen);
|
||||||
|
encryptCipher.update(in, out);
|
||||||
|
in.limit(in.capacity());
|
||||||
|
encryptCipher.doFinal(in, out);
|
||||||
|
out.flip();
|
||||||
|
in.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void decrypt() throws Exception {
|
||||||
|
decryptCipher.init(Cipher.DECRYPT_MODE, ks, spec);
|
||||||
|
decryptCipher.doFinal(encryptedData, out);
|
||||||
|
encryptedData.flip();
|
||||||
|
out.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void decryptMultiPart() throws Exception {
|
||||||
|
decryptCipher.init(Cipher.DECRYPT_MODE, ks, spec);
|
||||||
|
|
||||||
|
int len = encryptedData.remaining();
|
||||||
|
encryptedData.limit(updateLen);
|
||||||
|
decryptCipher.update(encryptedData, out);
|
||||||
|
encryptedData.limit(len);
|
||||||
|
|
||||||
|
decryptCipher.doFinal(encryptedData, out);
|
||||||
|
encryptedData.flip();
|
||||||
|
out.flip();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.javax.crypto.full;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This performance tests runs ChaCha20-Poly1305 encryption and decryption
|
||||||
|
* using input and output byte[] buffers with single and multi-part testing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CC20P1305Bench extends BenchBase {
|
||||||
|
|
||||||
|
public static final int IV_MODULO = 12;
|
||||||
|
|
||||||
|
public AlgorithmParameterSpec getNewSpec() {
|
||||||
|
iv_index = (iv_index + 1) % IV_MODULO;
|
||||||
|
return new IvParameterSpec(iv, iv_index, IV_MODULO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() throws Exception {
|
||||||
|
init("ChaCha20-Poly1305/None/NoPadding", keyLength);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.javax.crypto.full;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This performance tests runs ChaCha20-Poly1305 encryption and decryption
|
||||||
|
* using heap and direct ByteBuffers for input and output buffers with single
|
||||||
|
* and multi-part operations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CC20P1305ByteBuffer extends ByteBufferBase {
|
||||||
|
|
||||||
|
public static final int IV_MODULO = 12;
|
||||||
|
|
||||||
|
public AlgorithmParameterSpec getNewSpec() {
|
||||||
|
iv_index = (iv_index + 1) % IV_MODULO;
|
||||||
|
return new IvParameterSpec(iv, iv_index, IV_MODULO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() throws Exception {
|
||||||
|
init("ChaCha20-Poly1305/None/NoPadding", keyLength);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,14 +23,28 @@
|
|||||||
package org.openjdk.bench.javax.crypto.small;
|
package org.openjdk.bench.javax.crypto.small;
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Param;
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This small performance tests runs AES/GCM encryption and decryption
|
||||||
|
* using input and output byte[] buffers with single and multi-part testing.
|
||||||
|
* Only 1024 plaintext data length is tested.
|
||||||
|
*/
|
||||||
|
|
||||||
public class AESGCMBench extends
|
public class AESGCMBench extends
|
||||||
org.openjdk.bench.javax.crypto.full.AESGCMBench {
|
org.openjdk.bench.javax.crypto.full.AESGCMBench {
|
||||||
|
|
||||||
@Param({"128"})
|
@Param({"128"})
|
||||||
private int keyLength;
|
int keyLength;
|
||||||
|
|
||||||
@Param({"1024"})
|
@Param({"1024"})
|
||||||
private int dataSize;
|
int dataSize;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() throws Exception {
|
||||||
|
init("AES/GCM/NoPadding", keyLength, dataSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,14 +23,28 @@
|
|||||||
package org.openjdk.bench.javax.crypto.small;
|
package org.openjdk.bench.javax.crypto.small;
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Param;
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This small performance tests runs AES/GCM encryption and decryption
|
||||||
|
* using heap and direct ByteBuffers for input and output buffers with single
|
||||||
|
* and multi-part operations. Only 1024 plaintext data length is tested.
|
||||||
|
*/
|
||||||
|
|
||||||
public class AESGCMByteBuffer extends
|
public class AESGCMByteBuffer extends
|
||||||
org.openjdk.bench.javax.crypto.full.AESGCMByteBuffer {
|
org.openjdk.bench.javax.crypto.full.AESGCMByteBuffer {
|
||||||
|
|
||||||
@Param({"128"})
|
@Param({"128"})
|
||||||
private int keyLength;
|
int keyLength;
|
||||||
|
|
||||||
@Param({"1024"})
|
@Param({"1024"})
|
||||||
private int dataSize;
|
int dataSize;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() throws Exception {
|
||||||
|
init("AES/GCM/NoPadding", keyLength, dataSize);
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.javax.crypto.small;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This small performance tests runs ChaCha20-Poly1305 encryption and decryption
|
||||||
|
* using input and output byte[] buffers with single and multi-part testing.
|
||||||
|
* Only 1024 plaintext data length is tested.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CC20P1305Bench extends
|
||||||
|
org.openjdk.bench.javax.crypto.full.CC20P1305Bench {
|
||||||
|
|
||||||
|
@Param({"1024"})
|
||||||
|
int dataSize;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() throws Exception {
|
||||||
|
init("ChaCha20-Poly1305/None/NoPadding", 256, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.javax.crypto.small;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Setup;
|
||||||
|
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This small performance tests runs ChaCha20-Poly1305 encryption and decryption
|
||||||
|
* using heap and direct ByteBuffers for input and output buffers with single
|
||||||
|
* and multi-part operations. Only 1024 plaintext data length is tested.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CC20P1305ByteBuffer extends
|
||||||
|
org.openjdk.bench.javax.crypto.full.CC20P1305ByteBuffer {
|
||||||
|
|
||||||
|
@Param({"1024"})
|
||||||
|
int dataSize;
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
public void setup() throws Exception {
|
||||||
|
init("ChaCha20-Poly1305/None/NoPadding", 256, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user