private void readHeaderFields()

in src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java [750:867]


  private void readHeaderFields(final CiphertextHeaders ciphertextHeaders) {
    cryptoAlgo_ = ciphertextHeaders.getCryptoAlgoId();

    final CiphertextType ciphertextType = ciphertextHeaders.getType();
    if (ciphertextType != CiphertextType.CUSTOMER_AUTHENTICATED_ENCRYPTED_DATA) {
      throw new BadCiphertextException("Invalid type in ciphertext.");
    }

    final byte[] messageId = ciphertextHeaders.getMessageId();

    if (!commitmentPolicy_.algorithmAllowedForDecrypt(cryptoAlgo_)) {
      throw new AwsCryptoException(
          "Configuration conflict. "
              + "Cannot decrypt message with ID "
              + messageId
              + " due to CommitmentPolicy "
              + commitmentPolicy_
              + " requiring only committed messages. Algorithm ID was "
              + cryptoAlgo_
              + ". See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/troubleshooting-migration.html");
    }

    if (maxEncryptedDataKeys_ > 0
        && ciphertextHeaders_.getEncryptedKeyBlobCount() > maxEncryptedDataKeys_) {
      throw new AwsCryptoException("Ciphertext encrypted data keys exceed maxEncryptedDataKeys");
    }

    if (!signaturePolicy_.algorithmAllowedForDecrypt(cryptoAlgo_)) {
      throw new AwsCryptoException(
          "Configuration conflict. "
              + "Cannot decrypt message with ID "
              + messageId
              + " because AwsCrypto.createUnsignedMessageDecryptingStream() "
              + " accepts only unsigned messages. Algorithm ID was "
              + cryptoAlgo_
              + ".");
    }

    DecryptionMaterialsRequest request =
        DecryptionMaterialsRequest.newBuilder()
            .setAlgorithm(cryptoAlgo_)
            .setEncryptionContext(ciphertextHeaders.getEncryptionContextMap())
            .setReproducedEncryptionContext(reproducedEncryptionContext_)
            .setEncryptedDataKeys(ciphertextHeaders.getEncryptedKeyBlobs())
            .build();

    DecryptionMaterialsHandler result = cmmHandler_.decryptMaterials(request, commitmentPolicy_);

    encryptionContext_ = result.getEncryptionContext();

    List<String> reqKeys = result.getRequiredEncryptionContextKeys();
    Map<String, String> reqEncryptionContext =
        encryptionContext_.entrySet().stream()
            .filter(x -> reqKeys.contains(x.getKey()))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    // The authenticated only encryption context is all encryption context key-value pairs where the
    // key exists in Required Encryption Context Keys. It is then serialized according to the
    // message header Key Value Pairs.
    final byte[] authOnlyEncryptionContext =
        EncryptionContextSerializer.serialize(reqEncryptionContext);

    //noinspection unchecked
    dataKey_ = (DataKey<K>) result.getDataKey();
    PublicKey trailingPublicKey = result.getTrailingSignatureKey();

    try {
      decryptionKey_ =
          cryptoAlgo_.getEncryptionKeyFromDataKey(dataKey_.getKey(), ciphertextHeaders);
    } catch (final InvalidKeyException ex) {
      throw new AwsCryptoException(ex);
    }

    if (cryptoAlgo_.getTrailingSignatureLength() > 0) {
      Utils.assertNonNull(trailingPublicKey, "trailing public key");

      TrailingSignatureAlgorithm trailingSignatureAlgorithm =
          TrailingSignatureAlgorithm.forCryptoAlgorithm(cryptoAlgo_);

      try {
        trailingSig_ = Signature.getInstance(trailingSignatureAlgorithm.getHashAndSignAlgorithm());

        trailingSig_.initVerify(trailingPublicKey);
      } catch (GeneralSecurityException e) {
        throw new AwsCryptoException(e);
      }
    } else {
      if (trailingPublicKey != null) {
        throw new AwsCryptoException("Unexpected trailing signature key in context");
      }

      trailingSig_ = null;
    }

    final ContentType contentType = ciphertextHeaders.getContentType();

    final short nonceLen = ciphertextHeaders.getNonceLength();
    final int frameLen = ciphertextHeaders.getFrameLength();

    verifyHeaderIntegrity(ciphertextHeaders, authOnlyEncryptionContext);

    switch (contentType) {
      case FRAME:
        contentCryptoHandler_ =
            new FrameDecryptionHandler(
                decryptionKey_, (byte) nonceLen, cryptoAlgo_, messageId, frameLen);
        break;
      case SINGLEBLOCK:
        contentCryptoHandler_ =
            new BlockDecryptionHandler(decryptionKey_, (byte) nonceLen, cryptoAlgo_, messageId);
        break;
      default:
        // should never get here because an invalid content type is
        // detected when parsing.
        break;
    }

    ciphertextHeadersParsed_ = true;
  }