// Path: jwe/callout/src/main/java/com/apigee/utils/TemplateString.java
// public class TemplateString {
//     private final Pattern tmpltPattern =
//         Pattern.compile("\\{([^\\}]+)\\}", Pattern.CASE_INSENSITIVE);
//     public ArrayList<String> variableNames;
//     public String template;
//     private void injectDollar(int position) {
//         template =
//             template.substring(0, position) +
//             "$" + template.substring(position, template.length());
//     }
//     public TemplateString(String s) {
//         this.variableNames = new ArrayList<String>();
//         examineString(s);
//     }
// 
//     private void examineString(String input) {
//         this.template = input;
//         int x = 0;
//         Matcher m = tmpltPattern.matcher(input);
//         while (m.find()) {
//             variableNames.add(m.group(1));
//             injectDollar(m.start() + x++);
//         }
//     }
// }


import com.apigee.flow.execution.ExecutionContext;
import com.apigee.flow.execution.ExecutionResult;
import com.apigee.flow.execution.IOIntensive;
import com.apigee.flow.execution.spi.Execution;
import com.apigee.flow.message.MessageContext;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.IOException;
import java.io.InputStream;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwe.JsonWebEncryption;
import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
import org.apache.commons.ssl.PKCS8Key;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.text.StrSubstitutor;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.KeyFactory;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import com.apigee.utils.TemplateString;
        // If the provided data is encrypted, we need a password to decrypt
        // it. If the InputStream is not encrypted, then the password is ignored
        // (can be null).  The InputStream can be DER (raw ASN.1) or PEM (base64).
        PKCS8Key pkcs8 = new PKCS8Key( keyBytes, passwd.toCharArray() );

        // If an unencrypted PKCS8 key was provided, then getDecryptedBytes()
        // actually returns exactly what was originally passed in (with no
        // changes).  If an OpenSSL key was provided, it gets reformatted as
        // PKCS #8.
        byte[] decrypted = pkcs8.getDecryptedBytes();
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec( decrypted );

        // A Java PrivateKey object is born.
        PrivateKey pk = null;
        if ( pkcs8.isDSA() ) {
            pk = KeyFactory.getInstance( "DSA" ).generatePrivate( spec );
        }
        else if ( pkcs8.isRSA() ) {
            pk = KeyFactory.getInstance( "RSA" ).generatePrivate( spec );
        }
        return pk;
    }

    // If the value of a property value contains open and close curlies, eg,
    // {apiproxy.name} or ABC-{apikey}, then "resolve" the value by de-referencing
    // the context variables whose names appear between curlies.
    private String resolvePropertyValue(String spec, MessageContext msgCtxt) {
        if (spec.indexOf('{') > -1 && spec.indexOf('}')>-1) {
            // Replace ALL curly-braced items in the spec string with
            // the value of the corresponding context variable.
// Path: jwe/callout/src/main/java/com/apigee/utils/TemplateString.java
// public class TemplateString {
//     private final Pattern tmpltPattern =
//         Pattern.compile("\\{([^\\}]+)\\}", Pattern.CASE_INSENSITIVE);
//     public ArrayList<String> variableNames;
//     public String template;
//     private void injectDollar(int position) {
//         template =
//             template.substring(0, position) +
//             "$" + template.substring(position, template.length());
//     }
//     public TemplateString(String s) {
//         this.variableNames = new ArrayList<String>();
//         examineString(s);
//     }
// 
//     private void examineString(String input) {
//         this.template = input;
//         int x = 0;
//         Matcher m = tmpltPattern.matcher(input);
//         while (m.find()) {
//             variableNames.add(m.group(1));
//             injectDollar(m.start() + x++);
//         }
//     }
// }


// Path: jwe/callout/src/main/java/com/apigee/callout/jwe/JweEncryptorCallout.java
import com.apigee.flow.execution.ExecutionContext;
import com.apigee.flow.execution.ExecutionResult;
import com.apigee.flow.execution.IOIntensive;
import com.apigee.flow.execution.spi.Execution;
import com.apigee.flow.message.MessageContext;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.IOException;
import java.io.InputStream;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwe.JsonWebEncryption;
import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
import org.apache.commons.ssl.PKCS8Key;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.text.StrSubstitutor;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.KeyFactory;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import com.apigee.utils.TemplateString;

        // If the provided data is encrypted, we need a password to decrypt
        // it. If the InputStream is not encrypted, then the password is ignored
        // (can be null).  The InputStream can be DER (raw ASN.1) or PEM (base64).
        PKCS8Key pkcs8 = new PKCS8Key( keyBytes, passwd.toCharArray() );

        // If an unencrypted PKCS8 key was provided, then getDecryptedBytes()
        // actually returns exactly what was originally passed in (with no
        // changes).  If an OpenSSL key was provided, it gets reformatted as
        // PKCS #8.
        byte[] decrypted = pkcs8.getDecryptedBytes();
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec( decrypted );

        // A Java PrivateKey object is born.
        PrivateKey pk = null;
        if ( pkcs8.isDSA() ) {
            pk = KeyFactory.getInstance( "DSA" ).generatePrivate( spec );
        }
        else if ( pkcs8.isRSA() ) {
            pk = KeyFactory.getInstance( "RSA" ).generatePrivate( spec );
        }
        return pk;
    }

    // If the value of a property value contains open and close curlies, eg,
    // {apiproxy.name} or ABC-{apikey}, then "resolve" the value by de-referencing
    // the context variables whose names appear between curlies.
    private String resolvePropertyValue(String spec, MessageContext msgCtxt) {
        if (spec.indexOf('{') > -1 && spec.indexOf('}')>-1) {
            // Replace ALL curly-braced items in the spec string with
            // the value of the corresponding context variable.
            TemplateString ts = new TemplateString(spec);