mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8318756: Create better internal buffer for AEADs
Reviewed-by: djelinski
This commit is contained in:
parent
a9cb120d03
commit
dc9c77bebe
14 changed files with 1178 additions and 450 deletions
|
@ -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;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
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_BLK_SIZE = 64;
|
||||
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
|
||||
private boolean initialized;
|
||||
|
@ -650,7 +648,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
try {
|
||||
engine.doUpdate(in, inOfs, inLen, out, 0);
|
||||
} catch (ShortBufferException | KeyException exc) {
|
||||
throw new RuntimeException(exc);
|
||||
throw new ProviderException(exc);
|
||||
}
|
||||
|
||||
return out;
|
||||
|
@ -681,11 +679,35 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
try {
|
||||
bytesUpdated = engine.doUpdate(in, inOfs, inLen, out, outOfs);
|
||||
} catch (KeyException ke) {
|
||||
throw new RuntimeException(ke);
|
||||
throw new ProviderException(ke);
|
||||
}
|
||||
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
|
||||
* data provided by the caller.
|
||||
|
@ -753,6 +775,118 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
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.
|
||||
*
|
||||
|
@ -1243,6 +1377,11 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
*/
|
||||
int doFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff)
|
||||
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 {
|
||||
|
@ -1285,6 +1424,22 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
int outOff) throws ShortBufferException, KeyException {
|
||||
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 {
|
||||
|
@ -1348,11 +1503,32 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
aadDone = false;
|
||||
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 ByteArrayOutputStream cipherBuf;
|
||||
private AEADBufferedStream cipherBuf = null;
|
||||
private final byte[] tag;
|
||||
|
||||
@Override
|
||||
|
@ -1364,20 +1540,32 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
// size.
|
||||
return (isFinal ?
|
||||
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 {
|
||||
initAuthenticator();
|
||||
initCounterValue = 1;
|
||||
counter = initCounterValue;
|
||||
cipherBuf = new ByteArrayOutputStream(CIPHERBUF_BASE);
|
||||
tag = new byte[TAG_LENGTH];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doUpdate(byte[] in, int inOff, int inLen, byte[] out,
|
||||
int outOff) {
|
||||
int outOff) {
|
||||
if (initialized) {
|
||||
// If this is the first update since AAD updates, signal that
|
||||
// we're done processing AAD info and pad the AAD to a multiple
|
||||
|
@ -1389,6 +1577,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
|
||||
if (in != null) {
|
||||
Objects.checkFromIndexSize(inOff, inLen, in.length);
|
||||
initBuffer(inLen);
|
||||
cipherBuf.write(in, inOff, inLen);
|
||||
}
|
||||
} else {
|
||||
|
@ -1399,6 +1588,14 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int doUpdate(ByteBuffer input, ByteBuffer output) {
|
||||
initBuffer(input.remaining());
|
||||
cipherBuf.write(input);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doFinal(byte[] in, int inOff, int inLen, byte[] out,
|
||||
int outOff) throws ShortBufferException, AEADBadTagException,
|
||||
|
@ -1406,7 +1603,7 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
|
||||
byte[] ctPlusTag;
|
||||
int ctPlusTagLen;
|
||||
if (cipherBuf.size() == 0 && inOff == 0) {
|
||||
if (getBufferedLength() == 0) {
|
||||
// No previous data has been seen before doFinal, so we do
|
||||
// not need to hold any ciphertext in a buffer. We can
|
||||
// process it directly from the "in" parameter.
|
||||
|
@ -1415,10 +1612,11 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
ctPlusTagLen = inLen;
|
||||
} else {
|
||||
doUpdate(in, inOff, inLen, out, outOff);
|
||||
ctPlusTag = cipherBuf.toByteArray();
|
||||
ctPlusTagLen = ctPlusTag.length;
|
||||
ctPlusTag = cipherBuf.getBuffer();
|
||||
inOff = 0;
|
||||
ctPlusTagLen = cipherBuf.size();
|
||||
cipherBuf.reset();
|
||||
}
|
||||
cipherBuf.reset();
|
||||
|
||||
// There must at least be a tag length's worth of ciphertext
|
||||
// data in the buffered input.
|
||||
|
@ -1436,19 +1634,80 @@ abstract class ChaCha20Cipher extends CipherSpi {
|
|||
|
||||
// Calculate and compare the tag. Only do the decryption
|
||||
// if and only if the tag matches.
|
||||
authFinalizeData(ctPlusTag, 0, ctLen, tag, 0);
|
||||
long tagCompare = ((long)asLongView.get(ctPlusTag, ctLen) ^
|
||||
authFinalizeData(ctPlusTag, inOff, ctLen, tag, 0);
|
||||
long tagCompare = ((long)asLongView.get(ctPlusTag, ctLen + inOff) ^
|
||||
(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));
|
||||
if (tagCompare != 0) {
|
||||
throw new AEADBadTagException("Tag mismatch");
|
||||
}
|
||||
chaCha20Transform(ctPlusTag, 0, ctLen, out, outOff);
|
||||
chaCha20Transform(ctPlusTag, inOff, ctLen, out, outOff);
|
||||
aadDone = false;
|
||||
|
||||
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 {
|
||||
|
|
|
@ -40,8 +40,6 @@ import javax.crypto.IllegalBlockSizeException;
|
|||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.ShortBufferException;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -249,7 +247,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
protected AlgorithmParameters engineGetParameters() {
|
||||
GCMParameterSpec spec;
|
||||
spec = new GCMParameterSpec(tagLenBytes * 8,
|
||||
iv == null ? createIv(random) : iv.clone());
|
||||
iv == null ? createIv(random) : iv); // iv.clone() not necessary
|
||||
try {
|
||||
AlgorithmParameters params =
|
||||
AlgorithmParameters.getInstance("GCM",
|
||||
|
@ -680,12 +678,12 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
final int blockSize;
|
||||
|
||||
// buffer for AAD data; if null, meaning update has been called
|
||||
ByteArrayOutputStream aadBuffer = null;
|
||||
AEADBufferedStream aadBuffer = null;
|
||||
int sizeOfAAD = 0;
|
||||
boolean aadProcessed = false;
|
||||
|
||||
// buffer data for crypto operation
|
||||
ByteArrayOutputStream ibuffer = null;
|
||||
AEADBufferedStream ibuffer = null;
|
||||
|
||||
// Original dst buffer if there was an overlap situation
|
||||
ByteBuffer originalDst = null;
|
||||
|
@ -736,7 +734,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
// Initialize internal data buffer, if not already.
|
||||
void initBuffer(int len) {
|
||||
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
|
||||
*
|
||||
|
@ -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
|
||||
* supplied before beginning operations on the ciphertext (via the
|
||||
* {@code update} and {@code doFinal} methods).
|
||||
|
@ -843,7 +827,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
|
||||
if (aadBuffer == null) {
|
||||
if (sizeOfAAD == 0 && !aadProcessed) {
|
||||
aadBuffer = new ByteArrayOutputStream(len);
|
||||
aadBuffer = new AEADBufferedStream(len);
|
||||
} else {
|
||||
// update has already been called
|
||||
throw new IllegalStateException
|
||||
|
@ -856,18 +840,17 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
// Feed the AAD data to GHASH, pad if necessary
|
||||
void processAAD() {
|
||||
if (aadBuffer != null) {
|
||||
if (aadBuffer.size() > 0) {
|
||||
byte[] aad = aadBuffer.toByteArray();
|
||||
sizeOfAAD = aad.length;
|
||||
|
||||
int lastLen = aad.length % blockSize;
|
||||
sizeOfAAD = aadBuffer.size();
|
||||
if (sizeOfAAD > 0) {
|
||||
byte[] aad = aadBuffer.getBuffer();
|
||||
int lastLen = sizeOfAAD % blockSize;
|
||||
if (lastLen != 0) {
|
||||
ghash.update(aad, 0, aad.length - lastLen);
|
||||
ghash.update(aad, 0, sizeOfAAD - lastLen);
|
||||
byte[] padded = expandToOneBlock(aad,
|
||||
aad.length - lastLen, lastLen, blockSize);
|
||||
sizeOfAAD - lastLen, lastLen, blockSize);
|
||||
ghash.update(padded);
|
||||
} else {
|
||||
ghash.update(aad);
|
||||
ghash.update(aad, 0, sizeOfAAD);
|
||||
}
|
||||
}
|
||||
aadBuffer = null;
|
||||
|
@ -1147,7 +1130,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
|
||||
// if there is enough data in the ibuffer and 'in', encrypt it.
|
||||
if (bLen > 0) {
|
||||
byte[] buffer = ibuffer.toByteArray();
|
||||
byte[] buffer = ibuffer.getBuffer();
|
||||
// number of bytes not filling a block
|
||||
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) {
|
||||
int r = GaloisCounterMode.implGCMCrypt(in, inOfs, inLen, out,
|
||||
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
|
||||
if (src.remaining() >= remainder) {
|
||||
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);
|
||||
src.get(block, bLen, remainder);
|
||||
len += op.update(ByteBuffer.wrap(block, 0, blockSize),
|
||||
|
@ -1251,14 +1235,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
// Write the remaining bytes into the 'ibuffer'
|
||||
if (srcLen > 0) {
|
||||
initBuffer(srcLen);
|
||||
byte[] b = new byte[srcLen];
|
||||
src.get(b);
|
||||
// remainder offset is based on original buffer length
|
||||
try {
|
||||
ibuffer.write(b);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ibuffer.write(src);
|
||||
}
|
||||
|
||||
restoreDst(dst);
|
||||
|
@ -1290,13 +1268,13 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
|
||||
// process what is in the ibuffer
|
||||
if (bLen > 0) {
|
||||
byte[] buffer = ibuffer.toByteArray();
|
||||
byte[] buffer = ibuffer.getBuffer();
|
||||
|
||||
// Make a block if the remaining ibuffer and 'in' can make one.
|
||||
if (bLen + inLen >= blockSize) {
|
||||
int r;
|
||||
block = new byte[blockSize];
|
||||
r = mergeBlock(buffer, 0, in, inOfs, inLen, block);
|
||||
r = mergeBlock(buffer, 0, ibuffer.size(), in, inOfs, inLen, block);
|
||||
inOfs += r;
|
||||
inLen -= r;
|
||||
op.update(block, 0, blockSize, out, outOfs);
|
||||
|
@ -1353,7 +1331,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
if (len > 0) {
|
||||
processed += doLastBlock(op,
|
||||
(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
|
||||
|
@ -1427,9 +1406,10 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
tagLenBytes);
|
||||
} else {
|
||||
// tagOfs will be negative
|
||||
byte[] buffer = ibuffer.toByteArray();
|
||||
tagOfs = mergeBlock(buffer,
|
||||
buffer.length - (tagLenBytes - inLen), in, inOfs, inLen,
|
||||
byte[] buffer = ibuffer.getBuffer();
|
||||
int ofs = ibuffer.size() - (tagLenBytes - inLen);
|
||||
tagOfs = mergeBlock(buffer, ofs, ibuffer.size() - ofs,
|
||||
in, inOfs, inLen,
|
||||
tag) - tagLenBytes;
|
||||
}
|
||||
}
|
||||
|
@ -1475,15 +1455,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
src.remaining(), null, 0);
|
||||
src.position(src.limit());
|
||||
} else {
|
||||
byte[] b = new byte[src.remaining()];
|
||||
src.get(b);
|
||||
initBuffer(b.length);
|
||||
try {
|
||||
ibuffer.write(b);
|
||||
} catch (IOException e) {
|
||||
throw new ProviderException(
|
||||
"Unable to add remaining input to the buffer", e);
|
||||
}
|
||||
initBuffer(src.remaining());
|
||||
ibuffer.write(src);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -1491,7 +1464,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Override
|
||||
|
@ -1551,7 +1524,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Override
|
||||
|
@ -1568,7 +1541,8 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
|
||||
// Check if ibuffer has data
|
||||
if (getBufferedLength() != 0) {
|
||||
buffer = ByteBuffer.wrap(ibuffer.toByteArray());
|
||||
buffer = ByteBuffer.wrap(ibuffer.getBuffer(), 0,
|
||||
ibuffer.size());
|
||||
len += buffer.remaining();
|
||||
}
|
||||
|
||||
|
@ -1684,7 +1658,7 @@ abstract class GaloisCounterMode extends CipherSpi {
|
|||
}
|
||||
|
||||
if (bLen > 0) {
|
||||
buffer = ibuffer.toByteArray();
|
||||
buffer = ibuffer.getBuffer();
|
||||
|
||||
if (bLen >= PARALLEL_LEN) {
|
||||
len = GaloisCounterMode.implGCMCrypt(buffer, 0, bLen,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue