in src/main/java/com/amazonaws/encryptionsdk/internal/FrameDecryptionHandler.java [89:187]
public ProcessingSummary processBytes(
final byte[] in, final int off, final int len, final byte[] out, final int outOff)
throws BadCiphertextException, AwsCryptoException {
if (complete_) {
throw new AwsCryptoException("Ciphertext has already been processed.");
}
final long totalBytesToParse = unparsedBytes_.length + (long) len;
if (totalBytesToParse > Integer.MAX_VALUE) {
throw new AwsCryptoException(
"Integer overflow of the total bytes to parse and decrypt occured.");
}
final byte[] bytesToParse = new byte[(int) totalBytesToParse];
// If there were previously unparsed bytes, add them as the first
// set of bytes to be parsed in this call.
System.arraycopy(unparsedBytes_, 0, bytesToParse, 0, unparsedBytes_.length);
System.arraycopy(in, off, bytesToParse, unparsedBytes_.length, len);
int actualOutLen = 0;
int totalParsedBytes = 0;
// Parse available bytes. Stop parsing when there aren't enough
// bytes to complete parsing:
// - the ciphertext headers
// - the cipher frame
while (!complete_ && totalParsedBytes < bytesToParse.length) {
if (currentFrameHeaders_ == null) {
currentFrameHeaders_ = new CipherFrameHeaders();
currentFrameHeaders_.setNonceLength(nonceLen_);
if (frameSize_ == 0) {
// if frame size in ciphertext headers is 0, the frame size
// will need to be parsed in individual frame headers.
currentFrameHeaders_.includeFrameSize(true);
}
}
totalParsedBytes += currentFrameHeaders_.deserialize(bytesToParse, totalParsedBytes);
// if we have all frame fields, process the encrypted content.
if (currentFrameHeaders_.isComplete() == true) {
int protectedContentLen = -1;
if (currentFrameHeaders_.isFinalFrame()) {
protectedContentLen = currentFrameHeaders_.getFrameContentLength();
// The final frame should not be able to exceed the frameLength
if (frameSize_ > 0 && protectedContentLen > frameSize_) {
throw new BadCiphertextException("Final frame length exceeds frame length.");
}
} else {
protectedContentLen = frameSize_;
}
// include the tag which is added by the underlying cipher.
protectedContentLen += cryptoAlgo_.getTagLen();
if ((bytesToParse.length - totalParsedBytes) < protectedContentLen) {
// if we don't have all of the encrypted bytes, break
// until they become available.
break;
}
final byte[] bytesToDecrypt_ =
Arrays.copyOfRange(
bytesToParse, totalParsedBytes, totalParsedBytes + protectedContentLen);
totalParsedBytes += protectedContentLen;
if (frameNumber_ == Constants.MAX_FRAME_NUMBER) {
throw new BadCiphertextException("Frame number exceeds the maximum allowed value.");
}
final byte[] decryptedBytes = decryptContent(bytesToDecrypt_, 0, bytesToDecrypt_.length);
System.arraycopy(decryptedBytes, 0, out, (outOff + actualOutLen), decryptedBytes.length);
actualOutLen += decryptedBytes.length;
frameNumber_++;
complete_ = currentFrameHeaders_.isFinalFrame();
// reset frame headers as we are done processing current frame.
currentFrameHeaders_ = null;
} else {
// if there aren't enough bytes to parse cipher frame,
// we can't continue parsing.
break;
}
}
if (!complete_) {
// buffer remaining bytes for parsing in the next round.
unparsedBytes_ = Arrays.copyOfRange(bytesToParse, totalParsedBytes, bytesToParse.length);
return new ProcessingSummary(actualOutLen, len);
} else {
final ProcessingSummary result =
new ProcessingSummary(actualOutLen, totalParsedBytes - unparsedBytes_.length);
unparsedBytes_ = new byte[0];
return result;
}
}