public ProcessingSummary processBytes()

in src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java [494:607]


  public ProcessingSummary processBytes(
      final byte[] in, final int off, final int len, final byte[] out, final int outOff)
      throws BadCiphertextException, AwsCryptoException {

    // We should arguably check if we are already complete_ here as other handlers
    // like FrameDecryptionHandler and BlockDecryptionHandler do.
    // However, adding that now could potentially break customers who have extra trailing
    // bytes in their decryption streams.
    // The handlers are also inconsistent in general with this check. Even those that
    // do raise an exception here if already complete will not complain if
    // a single call to processBytes() completes the message and provides extra trailing bytes:
    // in that case they will just indicate that they didn't process the extra bytes instead.

    if (len < 0 || off < 0) {
      throw new AwsCryptoException(
          String.format("Invalid values for input offset: %d and length: %d", off, len));
    }

    if (in.length == 0 || len == 0) {
      return ProcessingSummary.ZERO;
    }

    final long totalBytesToParse = unparsedBytes_.length + (long) len;
    // check for integer overflow
    if (totalBytesToParse > Integer.MAX_VALUE) {
      throw new AwsCryptoException(
          "Size of the total bytes to parse and decrypt exceeded allowed maximum:"
              + Integer.MAX_VALUE);
    }

    checkSizeBound(len);
    ciphertextBytesSupplied_ += len;

    final byte[] bytesToParse = new byte[(int) totalBytesToParse];
    final int leftoverBytes = unparsedBytes_.length;
    // 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 totalParsedBytes = 0;
    if (!ciphertextHeadersParsed_) {
      totalParsedBytes += ciphertextHeaders_.deserialize(bytesToParse, 0, maxEncryptedDataKeys_);
      // When ciphertext headers are complete, we have the data
      // key and cipher mode to initialize the underlying cipher
      if (ciphertextHeaders_.isComplete() == true) {
        readHeaderFields(ciphertextHeaders_);
        updateTrailingSignature(ciphertextHeaders_);
        // reset unparsed bytes as parsing of ciphertext headers is
        // complete.
        unparsedBytes_ = new byte[0];
      } else {
        // If there aren't enough bytes to parse ciphertext
        // headers, we don't have anymore bytes to continue parsing.
        // But first copy the leftover bytes to unparsed bytes.
        unparsedBytes_ = Arrays.copyOfRange(bytesToParse, totalParsedBytes, bytesToParse.length);
        return new ProcessingSummary(0, len);
      }
    }

    int actualOutLen = 0;
    if (!contentCryptoHandler_.isComplete()) {
      // if there are bytes to parse further, pass it off to underlying
      // content cryptohandler.
      if ((bytesToParse.length - totalParsedBytes) > 0) {
        final ProcessingSummary contentResult =
            contentCryptoHandler_.processBytes(
                bytesToParse,
                totalParsedBytes,
                bytesToParse.length - totalParsedBytes,
                out,
                outOff);
        updateTrailingSignature(bytesToParse, totalParsedBytes, contentResult.getBytesProcessed());
        actualOutLen = contentResult.getBytesWritten();
        totalParsedBytes += contentResult.getBytesProcessed();
      }
      if (contentCryptoHandler_.isComplete()) {
        actualOutLen += contentCryptoHandler_.doFinal(out, outOff + actualOutLen);
      }
    }

    if (contentCryptoHandler_.isComplete()) {
      // If the crypto algorithm contains trailing signature, we will need to verify
      // the footer of the message.
      if (cryptoAlgo_.getTrailingSignatureLength() > 0) {
        totalParsedBytes += ciphertextFooters_.deserialize(bytesToParse, totalParsedBytes);
        if (ciphertextFooters_.isComplete()) {
          // reset unparsed bytes as parsing of the ciphertext footer is
          // complete.
          // This isn't strictly necessary since processing any further data
          // should be an error.
          unparsedBytes_ = new byte[0];

          try {
            if (!trailingSig_.verify(ciphertextFooters_.getMAuth())) {
              throw new BadCiphertextException("Bad trailing signature");
            }
          } catch (final SignatureException ex) {
            throw new BadCiphertextException("Bad trailing signature", ex);
          }
          complete_ = true;
        } else {
          // If there aren't enough bytes to parse the ciphertext
          // footer, we don't have any more bytes to continue parsing.
          // But first copy the leftover bytes to unparsed bytes.
          unparsedBytes_ = Arrays.copyOfRange(bytesToParse, totalParsedBytes, bytesToParse.length);
          return new ProcessingSummary(actualOutLen, len);
        }
      } else {
        complete_ = true;
      }
    }
    return new ProcessingSummary(actualOutLen, totalParsedBytes - leftoverBytes);
  }