public EncryptionHandler()

in src/main/java/com/amazonaws/encryptionsdk/internal/EncryptionHandler.java [78:210]


  public EncryptionHandler(
      int frameSize, EncryptionMaterialsHandler result, CommitmentPolicy commitmentPolicy)
      throws AwsCryptoException {
    Utils.assertNonNull(result, "result");
    Utils.assertNonNull(commitmentPolicy, "commitmentPolicy");

    this.encryptionMaterials_ = result;

    Map<String, String> encryptionContext = result.getEncryptionContext();
    List<String> reqKeys = result.getRequiredEncryptionContextKeys();
    Map<Boolean, Map<String, String>> partitionedEncryptionContext =
        encryptionContext.entrySet().stream()
            .collect(
                Collectors.partitioningBy(
                    entry -> reqKeys.contains(entry.getKey()),
                    Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));

    storedEncryptionContext_ = partitionedEncryptionContext.get(false);
    reqEncryptionContext_ = partitionedEncryptionContext.get(true);

    if (!commitmentPolicy.algorithmAllowedForEncrypt(result.getAlgorithm())) {
      if (commitmentPolicy == CommitmentPolicy.ForbidEncryptAllowDecrypt) {
        throw new AwsCryptoException(
            "Configuration conflict. Cannot encrypt due to CommitmentPolicy "
                + commitmentPolicy
                + " requiring only non-committed messages. Algorithm ID was "
                + result.getAlgorithm()
                + ". See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/troubleshooting-migration.html");
      } else {
        throw new AwsCryptoException(
            "Configuration conflict. Cannot encrypt due to CommitmentPolicy "
                + commitmentPolicy
                + " requiring only committed messages. Algorithm ID was "
                + result.getAlgorithm()
                + ". See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/troubleshooting-migration.html");
      }
    }
    this.cryptoAlgo_ = result.getAlgorithm();
    this.masterKeys_ = result.getMasterKeys();
    this.keyBlobs_ = result.getEncryptedDataKeys();
    this.trailingSignaturePrivateKey_ = result.getTrailingSignatureKey();

    if (keyBlobs_.isEmpty()) {
      throw new IllegalArgumentException("No encrypted data keys in materials result");
    }

    if (trailingSignaturePrivateKey_ != null) {
      try {
        TrailingSignatureAlgorithm algorithm =
            TrailingSignatureAlgorithm.forCryptoAlgorithm(cryptoAlgo_);
        trailingDigest_ = MessageDigest.getInstance(algorithm.getMessageDigestAlgorithm());
        trailingSig_ = Signature.getInstance(algorithm.getRawSignatureAlgorithm());

        trailingSig_.initSign(trailingSignaturePrivateKey_, Utils.getSecureRandom());
      } catch (final GeneralSecurityException ex) {
        throw new AwsCryptoException(ex);
      }
    } else {
      trailingDigest_ = null;
      trailingSig_ = null;
    }

    // set default values
    version_ = cryptoAlgo_.getMessageFormatVersion();
    type_ = CIPHERTEXT_TYPE;
    nonceLen_ = cryptoAlgo_.getNonceLen();

    ContentType contentType;
    if (frameSize > 0) {
      contentType = ContentType.FRAME;
    } else if (frameSize == 0) {
      contentType = ContentType.SINGLEBLOCK;
    } else {
      throw Utils.cannotBeNegative("Frame size");
    }

    // Construct the headers
    // Included here rather than as a sub-routine so we can set final variables.
    // This way we can avoid calculating the keys more times than we need.
    //
    // AAD: MUST be the serialization of the encryption context in the encryption materials, and
    // this serialization MUST NOT contain any key value pairs listed in the encryption material's
    // required encryption context keys.
    final byte[] storedEncryptionContextBytes =
        EncryptionContextSerializer.serialize(storedEncryptionContext_);
    final CiphertextHeaders unsignedHeaders =
        new CiphertextHeaders(
            type_, cryptoAlgo_, storedEncryptionContextBytes, keyBlobs_, contentType, frameSize);
    // We use a deterministic IV of zero for the header authentication.
    unsignedHeaders.setHeaderNonce(new byte[nonceLen_]);

    // If using a committing crypto algorithm, we also need to calculate the commitment value along
    // with the key derivation
    if (cryptoAlgo_.isCommitting()) {
      final CommittedKey committedKey =
          CommittedKey.generate(
              cryptoAlgo_, result.getCleartextDataKey(), unsignedHeaders.getMessageId());
      unsignedHeaders.setSuiteData(committedKey.getCommitment());
      encryptionKey_ = committedKey.getKey();
    } else {
      try {
        encryptionKey_ =
            cryptoAlgo_.getEncryptionKeyFromDataKey(result.getCleartextDataKey(), unsignedHeaders);
      } catch (final InvalidKeyException ex) {
        throw new AwsCryptoException(ex);
      }
    }

    // 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[] reqEncryptionContextBytes =
        EncryptionContextSerializer.serialize(reqEncryptionContext_);
    ciphertextHeaders_ = signCiphertextHeaders(unsignedHeaders, reqEncryptionContextBytes);
    ciphertextHeaderBytes_ = ciphertextHeaders_.toByteArray();
    byte[] messageId_ = ciphertextHeaders_.getMessageId();

    switch (contentType) {
      case FRAME:
        contentCryptoHandler_ =
            new FrameEncryptionHandler(
                encryptionKey_, nonceLen_, cryptoAlgo_, messageId_, frameSize);
        break;
      case SINGLEBLOCK:
        contentCryptoHandler_ =
            new BlockEncryptionHandler(encryptionKey_, nonceLen_, cryptoAlgo_, messageId_);
        break;
      default:
        // should never get here because a valid content type is always
        // set above based on the frame size.
        throw new AwsCryptoException("Unknown content type.");
    }
  }