public ProcessingSummary processBytes()

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;
    }
  }