You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ni...@apache.org on 2014/02/17 06:16:48 UTC

[2/3] git commit: CAMEL-7201 PGPDataFormat: allow caching of PGP keys via key access interface with thanks to Franz

CAMEL-7201 PGPDataFormat: allow caching of PGP keys via key access interface with thanks to Franz


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/62c8b7ad
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/62c8b7ad
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/62c8b7ad

Branch: refs/heads/master
Commit: 62c8b7ad2215668e8d45f874ab06a5d04aee19b5
Parents: 54172d6
Author: Willem Jiang <wi...@gmail.com>
Authored: Mon Feb 17 13:11:11 2014 +0800
Committer: Willem Jiang <wi...@gmail.com>
Committed: Mon Feb 17 13:11:11 2014 +0800

----------------------------------------------------------------------
 .../camel/converter/crypto/PGPDataFormat.java   | 624 ++----------------
 .../converter/crypto/PGPDataFormatUtil.java     |  74 +--
 .../crypto/PGPKeyAccessDataFormat.java          | 642 +++++++++++++++++++
 .../converter/crypto/PGPPublicKeyAccess.java    |  50 ++
 .../crypto/PGPPublicKeyAccessDefault.java       |  53 ++
 .../converter/crypto/PGPSecretKeyAccess.java    |  55 ++
 .../crypto/PGPSecretKeyAccessDefault.java       | 100 +++
 .../PGPSecretKeyAndPrivateKeyAndUserId.java     |  53 ++
 .../converter/crypto/PGPDataFormatTest.java     |  27 +
 .../crypto/PGPKeyAccessDataFormatTest.java      |  41 ++
 10 files changed, 1091 insertions(+), 628 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
index d7e92b2..6fcb961 100644
--- a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormat.java
@@ -16,134 +16,53 @@
  */
 package org.apache.camel.converter.crypto;
 
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.security.SignatureException;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.Exchange;
-import org.apache.camel.converter.crypto.PGPDataFormatUtil.PGPSecretKeyAndPrivateKeyAndUserId;
-import org.apache.camel.converter.stream.CachedOutputStream;
-import org.apache.camel.spi.DataFormat;
-import org.apache.camel.support.ServiceSupport;
-import org.apache.camel.util.ExchangeHelper;
-import org.apache.camel.util.IOHelper;
-import org.apache.camel.util.ObjectHelper;
-import org.bouncycastle.bcpg.ArmoredOutputStream;
-import org.bouncycastle.bcpg.CompressionAlgorithmTags;
-import org.bouncycastle.bcpg.HashAlgorithmTags;
-import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openpgp.PGPCompressedData;
-import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
-import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
-import org.bouncycastle.openpgp.PGPEncryptedDataList;
 import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.openpgp.PGPLiteralData;
-import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
-import org.bouncycastle.openpgp.PGPObjectFactory;
-import org.bouncycastle.openpgp.PGPOnePassSignature;
-import org.bouncycastle.openpgp.PGPOnePassSignatureList;
 import org.bouncycastle.openpgp.PGPPrivateKey;
 import org.bouncycastle.openpgp.PGPPublicKey;
-import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.bouncycastle.openpgp.PGPSignature;
-import org.bouncycastle.openpgp.PGPSignatureGenerator;
-import org.bouncycastle.openpgp.PGPSignatureList;
-import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
-import org.bouncycastle.openpgp.PGPUtil;
-import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
-import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
-import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
-import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
-import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * <code>PGPDataFormat</code> uses the <a
  * href="http://www.bouncycastle.org/java.htm">bouncy castle</a> libraries to
  * enable encryption and decryption in the PGP format.
+ * <p>
+ * See also {@link PGPKeyAccessDataFormat}.
+ * 
  */
-public class PGPDataFormat extends ServiceSupport implements DataFormat {
+public class PGPDataFormat extends PGPKeyAccessDataFormat implements PGPPublicKeyAccess, PGPSecretKeyAccess {
 
     public static final String KEY_FILE_NAME = "CamelPGPDataFormatKeyFileName";
     public static final String ENCRYPTION_KEY_RING = "CamelPGPDataFormatEncryptionKeyRing";
-    public static final String KEY_USERID = "CamelPGPDataFormatKeyUserid";
-    public static final String KEY_USERIDS = "CamelPGPDataFormatKeyUserids";
     public static final String KEY_PASSWORD = "CamelPGPDataFormatKeyPassword";
     public static final String SIGNATURE_KEY_FILE_NAME = "CamelPGPDataFormatSignatureKeyFileName";
     public static final String SIGNATURE_KEY_RING = "CamelPGPDataFormatSignatureKeyRing";
-    public static final String SIGNATURE_KEY_USERID = "CamelPGPDataFormatSignatureKeyUserid";
-    public static final String SIGNATURE_KEY_USERIDS = "CamelPGPDataFormatSignatureKeyUserids";
     public static final String SIGNATURE_KEY_PASSWORD = "CamelPGPDataFormatSignatureKeyPassword";
-    public static final String ENCRYPTION_ALGORITHM = "CamelPGPDataFormatEncryptionAlgorithm";
-    public static final String SIGNATURE_HASH_ALGORITHM = "CamelPGPDataFormatSignatureHashAlgorithm";
-    public static final String COMPRESSION_ALGORITHM = "CamelPGPDataFormatCompressionAlgorithm";
 
-    /**
-     * During encryption the number of asymmectirc encryption keys is set to
-     * this header parameter. The Value is of type Integer.
-     */
-    public static final String NUMBER_OF_ENCRYPTION_KEYS = "CamelPGPDataFormatNumberOfEncryptionKeys";
-    /**
-     * During signing the number of signing keys is set to this header
-     * parameter. This corresponds to the number of signatures. The Value is of
-     * type Integer.
-     */
-    public static final String NUMBER_OF_SIGNING_KEYS = "CamelPGPDataFormatNumberOfSigningKeys";
-
-    private static final Logger LOG = LoggerFactory.getLogger(PGPDataFormat.class);
-
-    private static final String BC = "BC";
-    private static final int BUFFER_SIZE = 16 * 1024;
-
-    // Java Cryptography Extension provider, default is Bouncy Castle
-    private String provider = BC;
+    //private static final Logger LOG = LoggerFactory.getLogger(PGPDataFormatChanged.class);
 
-    // encryption / decryption key info (required)
-    private String keyUserid; // only for encryption
-    //in addition you can specify further User IDs, in this case the symmetric key is encrypted by several public keys corresponding to the User Ids
-    private List<String> keyUserids; //only for encryption;
     private String password; // only for decryption
     private String keyFileName;
     // alternatively to the file name you can specify the key ring as byte array
     private byte[] encryptionKeyRing;
 
-    // signature / verification key info (optional)
-    private String signatureKeyUserid; // for signing and verification (optional for verification)
-    //For verification you can specify further User IDs in addition
-    private List<String> signatureKeyUserids; //only for signing with several keys and verifying;
     private String signaturePassword; //only for signing, optional if you have several signature keys, then you should use passphaseAccessor
     private String signatureKeyFileName;
     // alternatively to the signature key file name you can specify the signature key ring as byte array
     private byte[] signatureKeyRing;
 
-    private boolean armored; // for encryption
-    private boolean integrity = true; // for encryption
-
-    private int hashAlgorithm = HashAlgorithmTags.SHA1; // for encryption
-
-    private int algorithm = SymmetricKeyAlgorithmTags.CAST5; // for encryption
-
-    private int compressionAlgorithm = CompressionAlgorithmTags.ZIP; // for encryption
-
     private PGPPassphraseAccessor passphraseAccessor; // for signing and decryption with multiple keys
 
     public PGPDataFormat() {
+        super();
+        publicKeyAccess = this;
+        secretKeyAccess = this;
     }
 
     protected String findKeyFileName(Exchange exchange) {
@@ -154,15 +73,6 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         return exchange.getIn().getHeader(ENCRYPTION_KEY_RING, getEncryptionKeyRing(), byte[].class);
     }
 
-    protected String findKeyUserid(Exchange exchange) {
-        return exchange.getIn().getHeader(KEY_USERID, getKeyUserid(), String.class);
-    }
-
-    @SuppressWarnings("unchecked")
-    protected List<String> findKeyUserids(Exchange exchange) {
-        return exchange.getIn().getHeader(KEY_USERIDS, getKeyUserids(), List.class);
-    }
-
     protected String findKeyPassword(Exchange exchange) {
         return exchange.getIn().getHeader(KEY_PASSWORD, getPassword(), String.class);
         // the following lines are not needed because the passphrase accessor is taken into account later in the decryption case
@@ -181,15 +91,6 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         return exchange.getIn().getHeader(SIGNATURE_KEY_RING, getSignatureKeyRing(), byte[].class);
     }
 
-    protected String findSignatureKeyUserid(Exchange exchange) {
-        return exchange.getIn().getHeader(SIGNATURE_KEY_USERID, getSignatureKeyUserid(), String.class);
-    }
-
-    @SuppressWarnings("unchecked")
-    protected List<String> findSignatureKeyUserids(Exchange exchange) {
-        return exchange.getIn().getHeader(SIGNATURE_KEY_USERIDS, getSignatureKeyUserids(), List.class);
-    }
-
     protected String findSignatureKeyPassword(Exchange exchange) {
         String sigPassword = exchange.getIn().getHeader(SIGNATURE_KEY_PASSWORD, getSignaturePassword(), String.class);
         if (sigPassword != null) {
@@ -202,162 +103,6 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         }
     }
 
-    protected int findCompressionAlgorithm(Exchange exchange) {
-        return exchange.getIn().getHeader(COMPRESSION_ALGORITHM, getCompressionAlgorithm(), Integer.class);
-    }
-
-    protected int findAlgorithm(Exchange exchange) {
-        return exchange.getIn().getHeader(ENCRYPTION_ALGORITHM, getAlgorithm(), Integer.class);
-    }
-
-    protected int findHashAlgorithm(Exchange exchange) {
-        return exchange.getIn().getHeader(SIGNATURE_HASH_ALGORITHM, getHashAlgorithm(), Integer.class);
-    }
-
-    public void marshal(Exchange exchange, Object graph, OutputStream outputStream) throws Exception {
-        List<String> userids = determineEncryptionUserIds(exchange);
-        List<PGPPublicKey> keys = PGPDataFormatUtil.findPublicKeys(exchange.getContext(), findKeyFileName(exchange),
-                findEncryptionKeyRing(exchange), userids, true);
-        if (keys.isEmpty()) {
-            throw new IllegalArgumentException("Cannot PGP encrypt message. No public encryption key found for the User Ids " + userids
-                    + " in the public keyring. Either specify other User IDs or add correct public keys to the keyring.");
-        }
-        exchange.getOut().setHeader(NUMBER_OF_ENCRYPTION_KEYS, Integer.valueOf(keys.size()));
-
-        InputStream input = ExchangeHelper.convertToMandatoryType(exchange, InputStream.class, graph);
-
-        if (armored) {
-            outputStream = new ArmoredOutputStream(outputStream);
-        }
-
-        PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(findAlgorithm(exchange))
-                .setWithIntegrityPacket(integrity).setSecureRandom(new SecureRandom()).setProvider(getProvider()));
-        // several keys can be added
-        for (PGPPublicKey key : keys) {
-            encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(key));
-        }
-        OutputStream encOut = encGen.open(outputStream, new byte[BUFFER_SIZE]);
-
-        PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(findCompressionAlgorithm(exchange));
-        OutputStream comOut = new BufferedOutputStream(comData.open(encOut));
-
-        List<PGPSignatureGenerator> sigGens = createSignatureGenerator(exchange, comOut);
-
-        PGPLiteralDataGenerator litData = new PGPLiteralDataGenerator();
-        String fileName = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
-        if (ObjectHelper.isEmpty(fileName)) {
-            // This marks the file as For Your Eyes Only... may cause problems for the receiver if they use
-            // an automated process to decrypt as the filename is appended with _CONSOLE
-            fileName = PGPLiteralData.CONSOLE;
-        }
-        OutputStream litOut = litData.open(comOut, PGPLiteralData.BINARY, fileName, new Date(), new byte[BUFFER_SIZE]);
-
-        try {
-            byte[] buffer = new byte[BUFFER_SIZE];
-            int bytesRead;
-            while ((bytesRead = input.read(buffer)) != -1) {
-                litOut.write(buffer, 0, bytesRead);
-                if (sigGens != null && !sigGens.isEmpty()) {
-                    for (PGPSignatureGenerator sigGen : sigGens) {
-                        // not nested therefore it is the same for all
-                        // can this be improved that we only do it for one sigGen and set the result on the others?
-                        sigGen.update(buffer, 0, bytesRead);
-                    }
-                }
-                litOut.flush();
-            }
-        } finally {
-            IOHelper.close(litOut);
-            if (sigGens != null && !sigGens.isEmpty()) {
-                // reverse order
-                for (int i = sigGens.size() - 1; i > -1; i--) {
-                    PGPSignatureGenerator sigGen = sigGens.get(i);
-                    sigGen.generate().encode(comOut);
-                }
-            }
-            IOHelper.close(comOut, encOut, outputStream, input);
-        }
-    }
-
-    protected List<String> determineEncryptionUserIds(Exchange exchange) {
-        String userid = findKeyUserid(exchange);
-        List<String> userids = findKeyUserids(exchange);
-        // merge them together
-        List<String> result;
-        if (userid != null) {
-            if (userids == null || userids.isEmpty()) {
-                result = Collections.singletonList(userid);
-            } else {
-                result = new ArrayList<String>(userids.size() + 1);
-                result.add(userid);
-                result.addAll(userids);
-            }
-        } else {
-            if (userids == null || userids.isEmpty()) {
-                throw new IllegalStateException("Cannot PGP encrypt message. No User ID of the public key specified.");
-            }
-            result = userids;
-        }
-        return result;
-    }
-
-    protected List<String> determineSignaturenUserIds(Exchange exchange) {
-        String userid = findSignatureKeyUserid(exchange);
-        List<String> userids = findSignatureKeyUserids(exchange);
-        // merge them together
-        List<String> result;
-        if (userid != null) {
-            if (userids == null || userids.isEmpty()) {
-                result = Collections.singletonList(userid);
-            } else {
-                result = new ArrayList<String>(userids.size() + 1);
-                result.add(userid);
-                result.addAll(userids);
-            }
-        } else {
-            // userids can be empty or null!
-            result = userids;
-        }
-        return result;
-    }
-
-    protected List<PGPSignatureGenerator> createSignatureGenerator(Exchange exchange, OutputStream out) throws IOException, PGPException,
-            NoSuchProviderException, NoSuchAlgorithmException {
-
-        String sigKeyFileName = findSignatureKeyFileName(exchange);
-        List<String> sigKeyUserids = determineSignaturenUserIds(exchange);
-        String sigKeyPassword = findSignatureKeyPassword(exchange);
-        byte[] sigKeyRing = findSignatureKeyRing(exchange);
-
-        if ((sigKeyFileName == null && sigKeyRing == null) || sigKeyUserids == null || sigKeyUserids.isEmpty()
-                || (sigKeyPassword == null && passphraseAccessor == null)) {
-            return null;
-        }
-
-        List<PGPSecretKeyAndPrivateKeyAndUserId> sigSecretKeysWithPrivateKeyAndUserId = determineSecretKeysWithPrivateKeyAndUserId(
-                exchange, sigKeyFileName, sigKeyUserids, sigKeyPassword, sigKeyRing);
-
-        exchange.getOut().setHeader(NUMBER_OF_SIGNING_KEYS, Integer.valueOf(sigSecretKeysWithPrivateKeyAndUserId.size()));
-
-        List<PGPSignatureGenerator> sigGens = new ArrayList<PGPSignatureGenerator>();
-        for (PGPSecretKeyAndPrivateKeyAndUserId sigSecretKeyWithPrivateKeyAndUserId : sigSecretKeysWithPrivateKeyAndUserId) {
-            PGPPrivateKey sigPrivateKey = sigSecretKeyWithPrivateKeyAndUserId.getPrivateKey();
-
-            PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
-            spGen.setSignerUserID(false, sigSecretKeyWithPrivateKeyAndUserId.getUserId());
-
-            int algorithm = sigSecretKeyWithPrivateKeyAndUserId.getSecretKey().getPublicKey().getAlgorithm();
-            PGPSignatureGenerator sigGen = new PGPSignatureGenerator(
-                    new JcaPGPContentSignerBuilder(algorithm, findHashAlgorithm(exchange)).setProvider(getProvider()));
-            sigGen.init(PGPSignature.BINARY_DOCUMENT, sigPrivateKey);
-            sigGen.setHashedSubpackets(spGen.generate());
-            sigGen.generateOnePassVersion(false).encode(out);
-            sigGens.add(sigGen);
-        }
-        return sigGens;
-    }
-
-
     public List<PGPSecretKeyAndPrivateKeyAndUserId> determineSecretKeysWithPrivateKeyAndUserId(Exchange exchange, String sigKeyFileName,
             List<String> sigKeyUserids, String sigKeyPassword, byte[] sigKeyRing) throws IOException, PGPException, NoSuchProviderException {
 
@@ -394,213 +139,6 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         return sigKeyUserId2Password;
     }
 
-    @SuppressWarnings("resource")
-    public Object unmarshal(Exchange exchange, InputStream encryptedStream) throws Exception {
-        if (encryptedStream == null) {
-            return null;
-        }
-        InputStream in = PGPUtil.getDecoderStream(encryptedStream);
-        PGPObjectFactory pgpFactory = new PGPObjectFactory(in);
-        Object o = pgpFactory.nextObject();
-        // the first object might be a PGP marker packet 
-        PGPEncryptedDataList enc;
-        if (o instanceof PGPEncryptedDataList) {
-            enc = (PGPEncryptedDataList) o;
-        } else {
-            enc = (PGPEncryptedDataList) pgpFactory.nextObject();
-        }
-
-        PGPPublicKeyEncryptedData pbe = null;
-        PGPPrivateKey key = null;
-        // find encrypted data for which a private key exists in the secret key ring
-        for (int i = 0; i < enc.size() && key == null; i++) {
-            pbe = (PGPPublicKeyEncryptedData) enc.get(i);
-            key = PGPDataFormatUtil.findPrivateKeyWithKeyId(exchange.getContext(), findKeyFileName(exchange),
-                    findEncryptionKeyRing(exchange), pbe.getKeyID(), findKeyPassword(exchange), getPassphraseAccessor(), getProvider());
-            if (key != null) {
-                // take the first key
-                break;
-            }
-        }
-        if (key == null) {
-            throw new PGPException("Provided input is encrypted with unknown pair of keys.");
-        }
-
-        InputStream encData = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider(getProvider()).build(key));
-        pgpFactory = new PGPObjectFactory(encData);
-        PGPCompressedData comData = (PGPCompressedData) pgpFactory.nextObject();
-        pgpFactory = new PGPObjectFactory(comData.getDataStream());
-        Object object = pgpFactory.nextObject();
-
-        PGPOnePassSignature signature;
-        if (object instanceof PGPOnePassSignatureList) {
-            signature = getSignature(exchange, (PGPOnePassSignatureList) object);
-            object = pgpFactory.nextObject();
-        } else {
-            signature = null;
-        }
-
-        PGPLiteralData ld = (PGPLiteralData) object;
-        InputStream litData = ld.getInputStream();
-
-        // enable streaming via OutputStreamCache
-        CachedOutputStream cos;
-        ByteArrayOutputStream bos;
-        OutputStream os;
-        if (exchange.getContext().getStreamCachingStrategy().isEnabled()) {
-            cos = new CachedOutputStream(exchange);
-            bos = null;
-            os = cos;
-        } else {
-            cos = null;
-            bos = new ByteArrayOutputStream();
-            os = bos;
-        }
-
-        try {
-            byte[] buffer = new byte[BUFFER_SIZE];
-            int bytesRead;
-            while ((bytesRead = litData.read(buffer)) != -1) {
-                os.write(buffer, 0, bytesRead);
-                if (signature != null) {
-                    signature.update(buffer, 0, bytesRead);
-                }
-                os.flush();
-            }
-        } finally {
-            IOHelper.close(os, litData, encData, in);
-        }
-
-        if (signature != null) {
-            PGPSignatureList sigList = (PGPSignatureList) pgpFactory.nextObject();
-            if (!signature.verify(getSignatureWithKeyId(signature.getKeyID(), sigList))) {
-                throw new SignatureException("Cannot verify PGP signature");
-            }
-        }
-
-        if (cos != null) {
-            return cos.newStreamCache();
-        } else {
-            return bos.toByteArray();
-        }
-    }
-
-    protected PGPSignature getSignatureWithKeyId(long keyID, PGPSignatureList sigList) {
-        for (int i = 0; i < sigList.size(); i++) {
-            PGPSignature signature = sigList.get(i);
-            if (keyID == signature.getKeyID()) {
-                return signature;
-            }
-        }
-        throw new IllegalStateException("PGP signature is inconsistent");
-    }
-
-    protected PGPOnePassSignature getSignature(Exchange exchange, PGPOnePassSignatureList signatureList) throws IOException, PGPException,
-            NoSuchProviderException {
-
-        List<String> allowedUserIds = determineSignaturenUserIds(exchange);
-        for (int i = 0; i < signatureList.size(); i++) {
-            PGPOnePassSignature signature = signatureList.get(i);
-            // Determine public key from signature keyId
-            PGPPublicKey sigPublicKey = PGPDataFormatUtil.findPublicKeyWithKeyId(exchange.getContext(), findSignatureKeyFileName(exchange),
-                    findSignatureKeyRing(exchange), signature.getKeyID(), false);
-            if (sigPublicKey == null) {
-                continue;
-            }
-            if (isAllowedVerifyingKey(allowedUserIds, sigPublicKey)) {
-                // choose that signature for which a public key exists!
-                signature.init(new JcaPGPContentVerifierBuilderProvider().setProvider(getProvider()), sigPublicKey);
-                return signature;
-            }
-        }
-        if (signatureList.isEmpty()) {
-            return null;
-        } else {
-            throw new IllegalArgumentException("No public key found fitting to the signature key Id; cannot verify the signature");
-        }
-
-    }
-
-    public boolean isAllowedVerifyingKey(List<String> allowedUserIds, PGPPublicKey verifyingPublicKey) {
-
-        if (allowedUserIds == null || allowedUserIds.isEmpty()) {
-            // no restrictions specified
-            return true;
-        }
-        String keyUserId = null;
-        for (@SuppressWarnings("unchecked")
-        Iterator<String> iterator = verifyingPublicKey.getUserIDs(); iterator.hasNext();) {
-            keyUserId = iterator.next();
-            for (String userid : allowedUserIds) {
-                if (keyUserId != null && keyUserId.contains(userid)) {
-                    LOG.debug(
-                            "Public key with  user ID {} fulfills the User ID restriction {}. Therefore this key will be used for the signature verification. ",
-                            keyUserId, allowedUserIds);
-                    return true;
-                }
-            }
-        }
-        LOG.warn(
-                "Public key with User ID {} does not fulfill the User ID restriction {}. Therefore this key will not be used for the signature verification.",
-                keyUserId, allowedUserIds);
-        return false;
-    }
-
-    /**
-     * Sets if the encrypted file should be written in ascii visible text (for
-     * marshaling).
-     */
-    public void setArmored(boolean armored) {
-        this.armored = armored;
-    }
-
-    public boolean getArmored() {
-        return this.armored;
-    }
-
-    /**
-     * Whether or not to add an integrity check/sign to the encrypted file for
-     * marshaling.
-     */
-    public void setIntegrity(boolean integrity) {
-        this.integrity = integrity;
-    }
-
-    public boolean getIntegrity() {
-        return this.integrity;
-    }
-
-    /**
-     * User ID, or more precisely user ID part, of the key used for encryption.
-     * See also {@link #setKeyUserids(List<String>)}.
-     */
-    public void setKeyUserid(String keyUserid) {
-        this.keyUserid = keyUserid;
-    }
-
-    public String getKeyUserid() {
-        return keyUserid;
-    }
-
-    public List<String> getKeyUserids() {
-        return keyUserids;
-    }
-
-    /**
-     * Keys User IDs, or more precisely user ID parts, used for determining the
-     * public keys for encryption. If you just have one User ID, then you can
-     * also use the method {@link #setKeyUserid(String)}. The User ID specified
-     * in {@link #setKeyUserid(String)} and in this method will be merged
-     * together and the public keys which have a User ID which contain a value
-     * of the specified User IDs the will be used for the encryption. Be aware
-     * that you may get several public keys even if you specify only one User
-     * Id, because there can be several public keys which have a User ID which
-     * contains the specified User ID.
-     */
-    public void setKeyUserids(List<String> keyUserids) {
-        this.keyUserids = keyUserids;
-    }
-
     /**
      * Filename of the keyring that will be used for the encryption/decryption,
      * classpathResource. Alternatively you can provide the keyring also as byte
@@ -628,57 +166,6 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
     }
 
     /**
-     * Userid, or more precisely user ID part, of the signature key used for
-     * signing (marshal) and verifying (unmarshal). See also
-     * {@link #setSignatureKeyUserids(List)}.
-     */
-    public void setSignatureKeyUserid(String signatureKeyUserid) {
-        this.signatureKeyUserid = signatureKeyUserid;
-    }
-
-    public String getSignatureKeyUserid() {
-        return signatureKeyUserid;
-    }
-
-    public List<String> getSignatureKeyUserids() {
-        return signatureKeyUserids;
-    }
-
-    /**
-     * User IDs, or more precisely user ID parts, used for signing and
-     * verification.
-     * <p>
-     * In the signing case, the User IDs specify the private keys which are used
-     * for signing. If the result are several private keys then several
-     * signatures will be created. If you just have one signature User ID, then
-     * you can also use the method {@link #setSignatureKeyUserid(String)} or
-     * this method. The User ID specified in
-     * {@link #setSignatureKeyUserid(String)} and in this method will be merged
-     * together and the private keys which have a User Id which contain one
-     * value out of the specified UserIds will be used for the signature
-     * creation. Be aware that you may get several private keys even if you
-     * specify only one User Id, because there can be several private keys which
-     * have a User ID which contains the specified User ID.
-     * <p>
-     * In the verification case the User IDs restrict the set of public keys
-     * which can be used for verification. The public keys used for verification
-     * must contain a User ID which contain one value of the User ID list. If
-     * you neither specify in this method and nor specify in the method
-     * {@link #setSignatureKeyUserid(String)} any value then any public key in
-     * the public key ring will be taken into consideration for the
-     * verification.
-     * <p>
-     * If you just have one User ID, then you can also use the method
-     * {@link #setSignatureKeyUserid(String)}. The User ID specified in
-     * {@link #setSignatureKeyUserid(String)} and in this method will be merged
-     * together and the corresponding public keys represent the potential keys
-     * for the verification of the message.
-     */
-    public void setSignatureKeyUserids(List<String> signatureKeyUserids) {
-        this.signatureKeyUserids = signatureKeyUserids;
-    }
-
-    /**
      * Filename of the signature keyring that will be used, classpathResource.
      */
     public void setSignatureKeyFileName(String signatureKeyFileName) {
@@ -726,57 +213,6 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         this.signatureKeyRing = signatureKeyRing;
     }
 
-    public String getProvider() {
-        return provider;
-    }
-
-    /**
-     * Java Cryptography Extension (JCE) provider, default is Bouncy Castle
-     * ("BC"). Alternatively you can use, for example, the IAIK JCE provider; in
-     * this case the provider must be registered beforehand and the Bouncy
-     * Castle provider must not be registered beforehand. The Sun JCE provider
-     * does not work.
-     */
-    public void setProvider(String provider) {
-        this.provider = provider;
-    }
-
-    public int getCompressionAlgorithm() {
-        return compressionAlgorithm;
-    }
-
-    /**
-     * Compression algorithm used during marshaling. Possible values are defined
-     * in {@link CompressionAlgorithmTags}. Default value is ZIP.
-     */
-    public void setCompressionAlgorithm(int compressionAlgorithm) {
-        this.compressionAlgorithm = compressionAlgorithm;
-    }
-
-    public int getHashAlgorithm() {
-        return hashAlgorithm;
-    }
-
-    /**
-     * Digest algorithm for signing (marshaling). Possible values are defined in
-     * {@link HashAlgorithmTags}. Default value is SHA1.
-     */
-    public void setHashAlgorithm(int hashAlgorithm) {
-        this.hashAlgorithm = hashAlgorithm;
-    }
-
-    public int getAlgorithm() {
-        return algorithm;
-    }
-
-    /**
-     * Symmetric key algorithm for encryption (marshaling). Possible values are
-     * defined in {@link SymmetricKeyAlgorithmTags}. Default value is CAST5.
-     */
-    public void setAlgorithm(int algorithm) {
-        this.algorithm = algorithm;
-    }
-
     public PGPPassphraseAccessor getPassphraseAccessor() {
         return passphraseAccessor;
     }
@@ -795,17 +231,45 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
     }
 
     @Override
-    protected void doStart() throws Exception {
-        if (Security.getProvider(BC) == null && BC.equals(getProvider())) {
-            LOG.debug("Adding BouncyCastleProvider as security provider");
-            Security.addProvider(new BouncyCastleProvider());
-        } else {
-            LOG.debug("Using custom provider {} which is expected to be enlisted manually.", getProvider());
+    public List<PGPPublicKey> getEncryptionKeys(Exchange exchange, List<String> useridParts) throws Exception {
+        return PGPDataFormatUtil.findPublicKeys(exchange.getContext(), findKeyFileName(exchange), findEncryptionKeyRing(exchange),
+                useridParts, true);
+    }
+
+    @Override
+    public List<PGPSecretKeyAndPrivateKeyAndUserId> getSignerKeys(Exchange exchange, List<String> useridParts) throws Exception {
+        String sigKeyFileName = findSignatureKeyFileName(exchange);
+
+        String sigKeyPassword = findSignatureKeyPassword(exchange);
+        byte[] sigKeyRing = findSignatureKeyRing(exchange);
+
+        if ((sigKeyFileName == null && sigKeyRing == null) || useridParts == null || useridParts.isEmpty()
+                || (sigKeyPassword == null && passphraseAccessor == null)) {
+            return Collections.emptyList();
         }
+        return determineSecretKeysWithPrivateKeyAndUserId(exchange, sigKeyFileName, useridParts, sigKeyPassword, sigKeyRing);
+    }
+
+    @Override
+    public PGPPrivateKey getPrivateKey(Exchange exchange, long keyId) throws Exception {
+        return PGPDataFormatUtil.findPrivateKeyWithKeyId(exchange.getContext(), findKeyFileName(exchange), findEncryptionKeyRing(exchange),
+                keyId, findKeyPassword(exchange), getPassphraseAccessor(), getProvider());
+    }
+
+    @Override
+    public PGPPublicKey getPublicKey(Exchange exchange, long keyId) throws Exception {
+        return PGPDataFormatUtil.findPublicKeyWithKeyId(exchange.getContext(), findSignatureKeyFileName(exchange),
+                findSignatureKeyRing(exchange), keyId, false);
+    }
+
+    @Override
+    public void setPublicKeyAccess(PGPPublicKeyAccess publicKeyAccess) {
+        throw new UnsupportedOperationException("Use PGPKeyAccessDataFormat if you want to set the public key access");
     }
 
     @Override
-    protected void doStop() throws Exception {
-        // noop
+    public void setSecretKeyAccess(PGPSecretKeyAccess secretKeyAccess) {
+        throw new UnsupportedOperationException("Use PGPKeyAccessDataFormat if you want to set the secret key access");
     }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java
index b09ebe8..083729c 100644
--- a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPDataFormatUtil.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.converter.crypto;
 
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -56,6 +57,7 @@ import static org.bouncycastle.bcpg.PublicKeyAlgorithmTags.ELGAMAL_GENERAL;
 import static org.bouncycastle.bcpg.PublicKeyAlgorithmTags.RSA_GENERAL;
 import static org.bouncycastle.bcpg.PublicKeyAlgorithmTags.RSA_SIGN;
 
+
 public final class PGPDataFormatUtil {
 
     private static final Logger LOG = LoggerFactory.getLogger(PGPDataFormatUtil.class);
@@ -121,10 +123,14 @@ public final class PGPDataFormatUtil {
         }
     }
 
-    @SuppressWarnings("unchecked")
     private static PGPPrivateKey findPrivateKeyWithKeyId(InputStream keyringInput, long keyid, String passphrase,
             PGPPassphraseAccessor passphraseAccessor, String provider) throws IOException, PGPException {
         PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyringInput));
+        return findPrivateKeyWithkeyId(keyid, passphrase, passphraseAccessor, provider, pgpSec);
+    }
+
+    public static PGPPrivateKey findPrivateKeyWithkeyId(long keyid, String passphrase, PGPPassphraseAccessor passphraseAccessor,
+            String provider, PGPSecretKeyRingCollection pgpSec) throws PGPException {
         for (Iterator<?> i = pgpSec.getKeyRings(); i.hasNext();) {
             Object data = i.next();
             if (data instanceof PGPSecretKeyRing) {
@@ -133,6 +139,7 @@ public final class PGPDataFormatUtil {
                 if (secKey != null) {
                     if (passphrase == null && passphraseAccessor != null) {
                         // get passphrase from accessor // only primary/master key has user IDS
+                        @SuppressWarnings("unchecked")
                         Iterator<String> userIDs = keyring.getSecretKey().getUserIDs();
                         while (passphrase == null && userIDs.hasNext()) {
                             passphrase = passphraseAccessor.getPassphrase(userIDs.next());
@@ -173,31 +180,25 @@ public final class PGPDataFormatUtil {
         return is;
     }
 
-    @SuppressWarnings("unchecked")
     private static PGPPublicKey findPublicKeyWithKeyId(InputStream input, long keyid) throws IOException, PGPException,
             NoSuchProviderException {
         PGPPublicKeyRingCollection pgpSec = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input));
-
-        for (Iterator<PGPPublicKeyRing> keyRingIter = pgpSec.getKeyRings(); keyRingIter.hasNext();) {
-            PGPPublicKeyRing keyRing = keyRingIter.next();
-            PGPPublicKey key = keyRing.getPublicKey(keyid);
-            if (key != null) {
-                return key;
-            }
-
-        }
-
-        return null;
+        return pgpSec.getPublicKey(keyid);
     }
 
-    @SuppressWarnings("unchecked")
     private static List<PGPPublicKey> findPublicKeys(InputStream input, List<String> userids, boolean forEncryption) throws IOException,
             PGPException, NoSuchProviderException {
-        List<PGPPublicKey> result = new ArrayList<PGPPublicKey>(3);
 
         PGPPublicKeyRingCollection pgpSec = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input));
 
-        for (Iterator<PGPPublicKeyRing> keyRingIter = pgpSec.getKeyRings(); keyRingIter.hasNext();) {
+        return findPublicKeys(userids, forEncryption, pgpSec);
+    }
+
+    
+    @SuppressWarnings("unchecked")
+    public static List<PGPPublicKey> findPublicKeys(List<String> userids, boolean forEncryption, PGPPublicKeyRingCollection pgpPublicKeyringCollection) {
+        List<PGPPublicKey> result = new ArrayList<PGPPublicKey>(userids.size());
+        for (Iterator<PGPPublicKeyRing> keyRingIter = pgpPublicKeyringCollection.getKeyRings(); keyRingIter.hasNext();) {
             PGPPublicKeyRing keyRing = keyRingIter.next();
             Set<String> keyUserIds = getUserIds(keyRing);
             for (Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys(); keyIter.hasNext();) {
@@ -390,12 +391,16 @@ public final class PGPDataFormatUtil {
         return findSecretKey(context, keychainFilename, secKeyRing, passphrase, null, provider);
     }
 
-    @SuppressWarnings("unchecked")
     private static List<PGPSecretKeyAndPrivateKeyAndUserId> findSecretKeysWithPrivateKeyAndUserId(InputStream keyringInput,
             Map<String, String> sigKeyUserId2Password, String provider) throws IOException, PGPException, NoSuchProviderException {
-        List<PGPSecretKeyAndPrivateKeyAndUserId> result = new ArrayList<PGPDataFormatUtil.PGPSecretKeyAndPrivateKeyAndUserId>(
-                sigKeyUserId2Password.size());
         PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyringInput));
+        return findSecretKeysWithPrivateKeyAndUserId(sigKeyUserId2Password, provider, pgpSec);
+    }
+
+    public static List<PGPSecretKeyAndPrivateKeyAndUserId> findSecretKeysWithPrivateKeyAndUserId(Map<String, String> sigKeyUserId2Password,
+            String provider, PGPSecretKeyRingCollection pgpSec) throws PGPException {
+        List<PGPSecretKeyAndPrivateKeyAndUserId> result = new ArrayList<PGPSecretKeyAndPrivateKeyAndUserId>(
+                sigKeyUserId2Password.size());
         for (Iterator<?> i = pgpSec.getKeyRings(); i.hasNext();) {
             Object data = i.next();
             if (data instanceof PGPSecretKeyRing) {
@@ -405,7 +410,8 @@ public final class PGPDataFormatUtil {
                 for (String userIdPart : sigKeyUserId2Password.keySet()) {
                     for (String keyUserId : keyUserIds) {
                         if (keyUserId.contains(userIdPart)) {
-                            for (Iterator<PGPSecretKey> iterKey = keyring.getSecretKeys(); iterKey.hasNext();) {
+                            for (@SuppressWarnings("unchecked")
+                            Iterator<PGPSecretKey> iterKey = keyring.getSecretKeys(); iterKey.hasNext();) {
                                 PGPSecretKey secKey = iterKey.next();
                                 if (isSigningKey(secKey)) {
                                     PGPPrivateKey privateKey = secKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(
@@ -477,32 +483,4 @@ public final class PGPDataFormatUtil {
         }
         return null; // no key flag
     }
-
-    public static class PGPSecretKeyAndPrivateKeyAndUserId {
-
-        private final PGPSecretKey secretKey;
-
-        private final PGPPrivateKey privateKey;
-
-        private final String userId;
-
-        public PGPSecretKeyAndPrivateKeyAndUserId(PGPSecretKey secretKey, PGPPrivateKey privateKey, String userId) {
-            this.secretKey = secretKey;
-            this.privateKey = privateKey;
-            this.userId = userId;
-        }
-
-        public PGPSecretKey getSecretKey() {
-            return secretKey;
-        }
-
-        public PGPPrivateKey getPrivateKey() {
-            return privateKey;
-        }
-
-        public String getUserId() {
-            return userId;
-        }
-
-    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java
new file mode 100644
index 0000000..456bb7e
--- /dev/null
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPKeyAccessDataFormat.java
@@ -0,0 +1,642 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter.crypto;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.converter.stream.CachedOutputStream;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.support.ServiceSupport;
+import org.apache.camel.util.ExchangeHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.bouncycastle.bcpg.ArmoredOutputStream;
+import org.bouncycastle.bcpg.CompressionAlgorithmTags;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPCompressedData;
+import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
+import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
+import org.bouncycastle.openpgp.PGPEncryptedDataList;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPLiteralData;
+import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
+import org.bouncycastle.openpgp.PGPObjectFactory;
+import org.bouncycastle.openpgp.PGPOnePassSignature;
+import org.bouncycastle.openpgp.PGPOnePassSignatureList;
+import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureGenerator;
+import org.bouncycastle.openpgp.PGPSignatureList;
+import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
+import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
+import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
+import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This PGP Data Format uses the interfaces {@link PGPPublicKeyAccess} and
+ * {@link PGPSecretKeyAccess} to access the keys for encryption/signing and
+ * decryption/signature verification. These interfaces allow caching of the keys
+ * which can improve the performance.
+ * <p>
+ * If you want to provide the key access via keyrings in the format of a byte
+ * array or file, then you should use the class {@link PGPDataFormat}.
+ * 
+ */
+public class PGPKeyAccessDataFormat extends ServiceSupport implements DataFormat {
+
+    public static final String KEY_USERID = "CamelPGPDataFormatKeyUserid";
+    public static final String KEY_USERIDS = "CamelPGPDataFormatKeyUserids";
+    public static final String SIGNATURE_KEY_USERID = "CamelPGPDataFormatSignatureKeyUserid";
+    public static final String SIGNATURE_KEY_USERIDS = "CamelPGPDataFormatSignatureKeyUserids";
+    public static final String ENCRYPTION_ALGORITHM = "CamelPGPDataFormatEncryptionAlgorithm";
+    public static final String SIGNATURE_HASH_ALGORITHM = "CamelPGPDataFormatSignatureHashAlgorithm";
+    public static final String COMPRESSION_ALGORITHM = "CamelPGPDataFormatCompressionAlgorithm";
+
+    /**
+     * During encryption the number of asymmectirc encryption keys is set to
+     * this header parameter. The Value is of type Integer.
+     */
+    public static final String NUMBER_OF_ENCRYPTION_KEYS = "CamelPGPDataFormatNumberOfEncryptionKeys";
+    /**
+     * During signing the number of signing keys is set to this header
+     * parameter. This corresponds to the number of signatures. The Value is of
+     * type Integer.
+     */
+    public static final String NUMBER_OF_SIGNING_KEYS = "CamelPGPDataFormatNumberOfSigningKeys";
+
+    private static final Logger LOG = LoggerFactory.getLogger(PGPKeyAccessDataFormat.class);
+    
+
+    private static final String BC = "BC";
+    private static final int BUFFER_SIZE = 16 * 1024;
+    
+    PGPPublicKeyAccess publicKeyAccess;
+
+    PGPSecretKeyAccess secretKeyAccess;
+
+    // Java Cryptography Extension provider, default is Bouncy Castle
+    private String provider = BC;
+
+    // encryption / decryption key info (required)
+    private String keyUserid; // only for encryption
+    //in addition you can specify further User IDs, in this case the symmetric key is encrypted by several public keys corresponding to the User Ids
+    private List<String> keyUserids; //only for encryption;
+
+    // signature / verification key info (optional)
+    private String signatureKeyUserid; // for signing and verification (optional for verification)
+    //For verification you can specify further User IDs in addition
+    private List<String> signatureKeyUserids; //only for signing with several keys and verifying;
+
+    private boolean armored; // for encryption
+    private boolean integrity = true; // for encryption
+
+    private int hashAlgorithm = HashAlgorithmTags.SHA1; // for encryption
+
+    private int algorithm = SymmetricKeyAlgorithmTags.CAST5; // for encryption
+
+    private int compressionAlgorithm = CompressionAlgorithmTags.ZIP; // for encryption
+
+    public PGPKeyAccessDataFormat() {
+    }
+
+    protected String findKeyUserid(Exchange exchange) {
+        return exchange.getIn().getHeader(KEY_USERID, getKeyUserid(), String.class);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected List<String> findKeyUserids(Exchange exchange) {
+        return exchange.getIn().getHeader(KEY_USERIDS, getKeyUserids(), List.class);
+    }
+
+    protected String findSignatureKeyUserid(Exchange exchange) {
+        return exchange.getIn().getHeader(SIGNATURE_KEY_USERID, getSignatureKeyUserid(), String.class);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected List<String> findSignatureKeyUserids(Exchange exchange) {
+        return exchange.getIn().getHeader(SIGNATURE_KEY_USERIDS, getSignatureKeyUserids(), List.class);
+    }
+
+    protected int findCompressionAlgorithm(Exchange exchange) {
+        return exchange.getIn().getHeader(COMPRESSION_ALGORITHM, getCompressionAlgorithm(), Integer.class);
+    }
+
+    protected int findAlgorithm(Exchange exchange) {
+        return exchange.getIn().getHeader(ENCRYPTION_ALGORITHM, getAlgorithm(), Integer.class);
+    }
+
+    protected int findHashAlgorithm(Exchange exchange) {
+        return exchange.getIn().getHeader(SIGNATURE_HASH_ALGORITHM, getHashAlgorithm(), Integer.class);
+    }
+
+    public void marshal(Exchange exchange, Object graph, OutputStream outputStream) throws Exception {
+        List<String> userids = determineEncryptionUserIds(exchange);
+        List<PGPPublicKey> keys = publicKeyAccess.getEncryptionKeys(exchange, userids);
+        if (keys.isEmpty()) {
+            throw new IllegalArgumentException("Cannot PGP encrypt message. No public encryption key found for the User Ids " + userids
+                    + " in the public keyring. Either specify other User IDs or add correct public keys to the keyring.");
+        }
+        exchange.getOut().setHeader(NUMBER_OF_ENCRYPTION_KEYS, Integer.valueOf(keys.size()));
+
+        InputStream input = ExchangeHelper.convertToMandatoryType(exchange, InputStream.class, graph);
+
+        if (armored) {
+            outputStream = new ArmoredOutputStream(outputStream);
+        }
+
+        PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(new JcePGPDataEncryptorBuilder(findAlgorithm(exchange))
+                .setWithIntegrityPacket(integrity).setSecureRandom(new SecureRandom()).setProvider(getProvider()));
+        // several keys can be added
+        for (PGPPublicKey key : keys) {
+            encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(key));
+        }
+        OutputStream encOut = encGen.open(outputStream, new byte[BUFFER_SIZE]);
+
+        PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(findCompressionAlgorithm(exchange));
+        OutputStream comOut = new BufferedOutputStream(comData.open(encOut));
+
+        List<PGPSignatureGenerator> sigGens = createSignatureGenerator(exchange, comOut);
+
+        PGPLiteralDataGenerator litData = new PGPLiteralDataGenerator();
+        String fileName = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
+        if (ObjectHelper.isEmpty(fileName)) {
+            // This marks the file as For Your Eyes Only... may cause problems for the receiver if they use
+            // an automated process to decrypt as the filename is appended with _CONSOLE
+            fileName = PGPLiteralData.CONSOLE;
+        }
+        OutputStream litOut = litData.open(comOut, PGPLiteralData.BINARY, fileName, new Date(), new byte[BUFFER_SIZE]);
+
+        try {
+            byte[] buffer = new byte[BUFFER_SIZE];
+            int bytesRead;
+            while ((bytesRead = input.read(buffer)) != -1) {
+                litOut.write(buffer, 0, bytesRead);
+                if (sigGens != null && !sigGens.isEmpty()) {
+                    for (PGPSignatureGenerator sigGen : sigGens) {
+                        // not nested therefore it is the same for all
+                        // can this be improved that we only do it for one sigGen and set the result on the others?
+                        sigGen.update(buffer, 0, bytesRead);
+                    }
+                }
+                litOut.flush();
+            }
+        } finally {
+            IOHelper.close(litOut);
+            if (sigGens != null && !sigGens.isEmpty()) {
+                // reverse order
+                for (int i = sigGens.size() - 1; i > -1; i--) {
+                    PGPSignatureGenerator sigGen = sigGens.get(i);
+                    sigGen.generate().encode(comOut);
+                }
+            }
+            IOHelper.close(comOut, encOut, outputStream, input);
+        }
+    }
+
+    protected List<String> determineEncryptionUserIds(Exchange exchange) {
+        String userid = findKeyUserid(exchange);
+        List<String> userids = findKeyUserids(exchange);
+        // merge them together
+        List<String> result;
+        if (userid != null) {
+            if (userids == null || userids.isEmpty()) {
+                result = Collections.singletonList(userid);
+            } else {
+                result = new ArrayList<String>(userids.size() + 1);
+                result.add(userid);
+                result.addAll(userids);
+            }
+        } else {
+            if (userids == null || userids.isEmpty()) {
+                throw new IllegalStateException("Cannot PGP encrypt message. No User ID of the public key specified.");
+            }
+            result = userids;
+        }
+        return result;
+    }
+
+    protected List<String> determineSignaturenUserIds(Exchange exchange) {
+        String userid = findSignatureKeyUserid(exchange);
+        List<String> userids = findSignatureKeyUserids(exchange);
+        // merge them together
+        List<String> result;
+        if (userid != null) {
+            if (userids == null || userids.isEmpty()) {
+                result = Collections.singletonList(userid);
+            } else {
+                result = new ArrayList<String>(userids.size() + 1);
+                result.add(userid);
+                result.addAll(userids);
+            }
+        } else {
+            // userids can be empty or null!
+            result = userids;
+        }
+        return result;
+    }
+
+    protected List<PGPSignatureGenerator> createSignatureGenerator(Exchange exchange, OutputStream out) throws Exception {
+
+        if (secretKeyAccess == null) {
+            return null;
+        }
+
+        List<String> sigKeyUserids = determineSignaturenUserIds(exchange);
+        List<PGPSecretKeyAndPrivateKeyAndUserId> sigSecretKeysWithPrivateKeyAndUserId = secretKeyAccess.getSignerKeys(exchange,
+                sigKeyUserids);
+        if (sigSecretKeysWithPrivateKeyAndUserId.isEmpty()) {
+            return null;
+        }
+
+        exchange.getOut().setHeader(NUMBER_OF_SIGNING_KEYS, Integer.valueOf(sigSecretKeysWithPrivateKeyAndUserId.size()));
+
+        List<PGPSignatureGenerator> sigGens = new ArrayList<PGPSignatureGenerator>();
+        for (PGPSecretKeyAndPrivateKeyAndUserId sigSecretKeyWithPrivateKeyAndUserId : sigSecretKeysWithPrivateKeyAndUserId) {
+            PGPPrivateKey sigPrivateKey = sigSecretKeyWithPrivateKeyAndUserId.getPrivateKey();
+
+            PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+            spGen.setSignerUserID(false, sigSecretKeyWithPrivateKeyAndUserId.getUserId());
+
+            int algorithm = sigSecretKeyWithPrivateKeyAndUserId.getSecretKey().getPublicKey().getAlgorithm();
+            PGPSignatureGenerator sigGen = new PGPSignatureGenerator(
+                    new JcaPGPContentSignerBuilder(algorithm, findHashAlgorithm(exchange)).setProvider(getProvider()));
+            sigGen.init(PGPSignature.BINARY_DOCUMENT, sigPrivateKey);
+            sigGen.setHashedSubpackets(spGen.generate());
+            sigGen.generateOnePassVersion(false).encode(out);
+            sigGens.add(sigGen);
+        }
+        return sigGens;
+    }
+
+    @SuppressWarnings("resource")
+    public Object unmarshal(Exchange exchange, InputStream encryptedStream) throws Exception {
+        if (encryptedStream == null) {
+            return null;
+        }
+        InputStream in = PGPUtil.getDecoderStream(encryptedStream);
+        PGPObjectFactory pgpFactory = new PGPObjectFactory(in);
+        Object o = pgpFactory.nextObject();
+        // the first object might be a PGP marker packet 
+        PGPEncryptedDataList enc;
+        if (o instanceof PGPEncryptedDataList) {
+            enc = (PGPEncryptedDataList) o;
+        } else {
+            enc = (PGPEncryptedDataList) pgpFactory.nextObject();
+        }
+
+        PGPPublicKeyEncryptedData pbe = null;
+        PGPPrivateKey key = null;
+        // find encrypted data for which a private key exists in the secret key ring
+        for (int i = 0; i < enc.size() && key == null; i++) {
+            pbe = (PGPPublicKeyEncryptedData) enc.get(i);
+            key = secretKeyAccess.getPrivateKey(exchange, pbe.getKeyID());
+            if (key != null) {
+                // take the first key
+                break;
+            }
+        }
+        if (key == null) {
+            throw new PGPException("Provided input is encrypted with unknown pair of keys.");
+        }
+
+        InputStream encData = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider(getProvider()).build(key));
+        pgpFactory = new PGPObjectFactory(encData);
+        PGPCompressedData comData = (PGPCompressedData) pgpFactory.nextObject();
+        pgpFactory = new PGPObjectFactory(comData.getDataStream());
+        Object object = pgpFactory.nextObject();
+
+        PGPOnePassSignature signature;
+        if (object instanceof PGPOnePassSignatureList) {
+            signature = getSignature(exchange, (PGPOnePassSignatureList) object);
+            object = pgpFactory.nextObject();
+        } else {
+            signature = null;
+        }
+
+        PGPLiteralData ld = (PGPLiteralData) object;
+        InputStream litData = ld.getInputStream();
+
+        // enable streaming via OutputStreamCache
+        CachedOutputStream cos;
+        ByteArrayOutputStream bos;
+        OutputStream os;
+        if (exchange.getContext().getStreamCachingStrategy().isEnabled()) {
+            cos = new CachedOutputStream(exchange);
+            bos = null;
+            os = cos;
+        } else {
+            cos = null;
+            bos = new ByteArrayOutputStream();
+            os = bos;
+        }
+
+        try {
+            byte[] buffer = new byte[BUFFER_SIZE];
+            int bytesRead;
+            while ((bytesRead = litData.read(buffer)) != -1) {
+                os.write(buffer, 0, bytesRead);
+                if (signature != null) {
+                    signature.update(buffer, 0, bytesRead);
+                }
+                os.flush();
+            }
+        } finally {
+            IOHelper.close(os, litData, encData, in);
+        }
+
+        if (signature != null) {
+            PGPSignatureList sigList = (PGPSignatureList) pgpFactory.nextObject();
+            if (!signature.verify(getSignatureWithKeyId(signature.getKeyID(), sigList))) {
+                throw new SignatureException("Cannot verify PGP signature");
+            }
+        }
+
+        if (cos != null) {
+            return cos.newStreamCache();
+        } else {
+            return bos.toByteArray();
+        }
+    }
+
+    protected PGPSignature getSignatureWithKeyId(long keyID, PGPSignatureList sigList) {
+        for (int i = 0; i < sigList.size(); i++) {
+            PGPSignature signature = sigList.get(i);
+            if (keyID == signature.getKeyID()) {
+                return signature;
+            }
+        }
+        throw new IllegalStateException("PGP signature is inconsistent");
+    }
+
+    protected PGPOnePassSignature getSignature(Exchange exchange, PGPOnePassSignatureList signatureList) throws Exception {
+
+        List<String> allowedUserIds = determineSignaturenUserIds(exchange);
+        for (int i = 0; i < signatureList.size(); i++) {
+            PGPOnePassSignature signature = signatureList.get(i);
+            // Determine public key from signature keyId
+            PGPPublicKey sigPublicKey = publicKeyAccess.getPublicKey(exchange, signature.getKeyID());
+            if (sigPublicKey == null) {
+                continue;
+            }
+            if (isAllowedVerifyingKey(allowedUserIds, sigPublicKey)) {
+                // choose that signature for which a public key exists!
+                signature.init(new JcaPGPContentVerifierBuilderProvider().setProvider(getProvider()), sigPublicKey);
+                return signature;
+            }
+        }
+        if (signatureList.isEmpty()) {
+            return null;
+        } else {
+            throw new IllegalArgumentException("No public key found fitting to the signature key Id; cannot verify the signature");
+        }
+
+    }
+
+    public boolean isAllowedVerifyingKey(List<String> allowedUserIds, PGPPublicKey verifyingPublicKey) {
+
+        if (allowedUserIds == null || allowedUserIds.isEmpty()) {
+            // no restrictions specified
+            return true;
+        }
+        String keyUserId = null;
+        for (@SuppressWarnings("unchecked")
+        Iterator<String> iterator = verifyingPublicKey.getUserIDs(); iterator.hasNext();) {
+            keyUserId = iterator.next();
+            for (String userid : allowedUserIds) {
+                if (keyUserId != null && keyUserId.contains(userid)) {
+                    LOG.debug(
+                            "Public key with  user ID {} fulfills the User ID restriction {}. Therefore this key will be used for the signature verification. ",
+                            keyUserId, allowedUserIds);
+                    return true;
+                }
+            }
+        }
+        LOG.warn(
+                "Public key with User ID {} does not fulfill the User ID restriction {}. Therefore this key will not be used for the signature verification.",
+                keyUserId, allowedUserIds);
+        return false;
+    }
+
+    /**
+     * Sets if the encrypted file should be written in ascii visible text (for
+     * marshaling).
+     */
+    public void setArmored(boolean armored) {
+        this.armored = armored;
+    }
+
+    public boolean getArmored() {
+        return this.armored;
+    }
+
+    /**
+     * Whether or not to add an integrity check/sign to the encrypted file for
+     * marshaling.
+     */
+    public void setIntegrity(boolean integrity) {
+        this.integrity = integrity;
+    }
+
+    public boolean getIntegrity() {
+        return this.integrity;
+    }
+
+    /**
+     * User ID, or more precisely user ID part, of the key used for encryption.
+     * See also {@link #setKeyUserids(List<String>)}.
+     */
+    public void setKeyUserid(String keyUserid) {
+        this.keyUserid = keyUserid;
+    }
+
+    public String getKeyUserid() {
+        return keyUserid;
+    }
+
+    public List<String> getKeyUserids() {
+        return keyUserids;
+    }
+
+    /**
+     * Keys User IDs, or more precisely user ID parts, used for determining the
+     * public keys for encryption. If you just have one User ID, then you can
+     * also use the method {@link #setKeyUserid(String)}. The User ID specified
+     * in {@link #setKeyUserid(String)} and in this method will be merged
+     * together and the public keys which have a User ID which contain a value
+     * of the specified User IDs the will be used for the encryption. Be aware
+     * that you may get several public keys even if you specify only one User
+     * Id, because there can be several public keys which have a User ID which
+     * contains the specified User ID.
+     */
+    public void setKeyUserids(List<String> keyUserids) {
+        this.keyUserids = keyUserids;
+    }
+
+    /**
+     * Userid, or more precisely user ID part, of the signature key used for
+     * signing (marshal) and verifying (unmarshal). See also
+     * {@link #setSignatureKeyUserids(List)}.
+     */
+    public void setSignatureKeyUserid(String signatureKeyUserid) {
+        this.signatureKeyUserid = signatureKeyUserid;
+    }
+
+    public String getSignatureKeyUserid() {
+        return signatureKeyUserid;
+    }
+
+    public List<String> getSignatureKeyUserids() {
+        return signatureKeyUserids;
+    }
+
+    /**
+     * User IDs, or more precisely user ID parts, used for signing and
+     * verification.
+     * <p>
+     * In the signing case, the User IDs specify the private keys which are used
+     * for signing. If the result are several private keys then several
+     * signatures will be created. If you just have one signature User ID, then
+     * you can also use the method {@link #setSignatureKeyUserid(String)} or
+     * this method. The User ID specified in
+     * {@link #setSignatureKeyUserid(String)} and in this method will be merged
+     * together and the private keys which have a User Id which contain one
+     * value out of the specified UserIds will be used for the signature
+     * creation. Be aware that you may get several private keys even if you
+     * specify only one User Id, because there can be several private keys which
+     * have a User ID which contains the specified User ID.
+     * <p>
+     * In the verification case the User IDs restrict the set of public keys
+     * which can be used for verification. The public keys used for verification
+     * must contain a User ID which contain one value of the User ID list. If
+     * you neither specify in this method and nor specify in the method
+     * {@link #setSignatureKeyUserid(String)} any value then any public key in
+     * the public key ring will be taken into consideration for the
+     * verification.
+     * <p>
+     * If you just have one User ID, then you can also use the method
+     * {@link #setSignatureKeyUserid(String)}. The User ID specified in
+     * {@link #setSignatureKeyUserid(String)} and in this method will be merged
+     * together and the corresponding public keys represent the potential keys
+     * for the verification of the message.
+     */
+    public void setSignatureKeyUserids(List<String> signatureKeyUserids) {
+        this.signatureKeyUserids = signatureKeyUserids;
+    }
+
+    public String getProvider() {
+        return provider;
+    }
+
+    /**
+     * Java Cryptography Extension (JCE) provider, default is Bouncy Castle
+     * ("BC"). Alternatively you can use, for example, the IAIK JCE provider; in
+     * this case the provider must be registered beforehand and the Bouncy
+     * Castle provider must not be registered beforehand. The Sun JCE provider
+     * does not work.
+     */
+    public void setProvider(String provider) {
+        this.provider = provider;
+    }
+
+    public int getCompressionAlgorithm() {
+        return compressionAlgorithm;
+    }
+
+    /**
+     * Compression algorithm used during marshaling. Possible values are defined
+     * in {@link CompressionAlgorithmTags}. Default value is ZIP.
+     */
+    public void setCompressionAlgorithm(int compressionAlgorithm) {
+        this.compressionAlgorithm = compressionAlgorithm;
+    }
+
+    public int getHashAlgorithm() {
+        return hashAlgorithm;
+    }
+
+    /**
+     * Digest algorithm for signing (marshaling). Possible values are defined in
+     * {@link HashAlgorithmTags}. Default value is SHA1.
+     */
+    public void setHashAlgorithm(int hashAlgorithm) {
+        this.hashAlgorithm = hashAlgorithm;
+    }
+
+    public int getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * Symmetric key algorithm for encryption (marshaling). Possible values are
+     * defined in {@link SymmetricKeyAlgorithmTags}. Default value is CAST5.
+     */
+    public void setAlgorithm(int algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    public PGPPublicKeyAccess getPublicKeyAccess() {
+        return publicKeyAccess;
+    }
+
+    public void setPublicKeyAccess(PGPPublicKeyAccess publicKeyAccess) {
+        this.publicKeyAccess = publicKeyAccess;
+    }
+
+    public PGPSecretKeyAccess getSecretKeyAccess() {
+        return secretKeyAccess;
+    }
+
+    public void setSecretKeyAccess(PGPSecretKeyAccess secretKeyAccess) {
+        this.secretKeyAccess = secretKeyAccess;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        if (Security.getProvider(BC) == null && BC.equals(getProvider())) {
+            LOG.debug("Adding BouncyCastleProvider as security provider");
+            Security.addProvider(new BouncyCastleProvider());
+        } else {
+            LOG.debug("Using custom provider {} which is expected to be enlisted manually.", getProvider());
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        // noop
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPublicKeyAccess.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPublicKeyAccess.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPublicKeyAccess.java
new file mode 100644
index 0000000..0ee9f67
--- /dev/null
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPublicKeyAccess.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter.crypto;
+
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.bouncycastle.openpgp.PGPPublicKey;
+
+public interface PGPPublicKeyAccess {
+
+    /**
+     * Returns the encryption keys for the given user ID parts. This method is
+     * used for encryption.
+     * 
+     * @param exchange
+     *            exchange, can be <code>null</code>
+     * @param useridParts
+     *            parts of User IDs, must not be <code>null</code>
+     * @return list of public keys, must not be <code>null</code>
+     */
+    List<PGPPublicKey> getEncryptionKeys(Exchange exchange, List<String> useridParts) throws Exception;
+
+    /**
+     * Returns the public key with a certain key ID. This method is used for
+     * verifying the signature.
+     * 
+     * @param exchange
+     *            exchange
+     * @param keyId
+     *            key ID
+     * @return public key or <code>null</code> if the key cannot be found
+     */
+    PGPPublicKey getPublicKey(Exchange exchange, long keyId) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPublicKeyAccessDefault.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPublicKeyAccessDefault.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPublicKeyAccessDefault.java
new file mode 100644
index 0000000..5e05d04
--- /dev/null
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPublicKeyAccessDefault.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter.crypto;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.util.ObjectHelper;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
+import org.bouncycastle.openpgp.PGPUtil;
+
+/**
+ * Caches a public key ring.
+ * 
+ */
+public class PGPPublicKeyAccessDefault implements PGPPublicKeyAccess {
+
+    private final PGPPublicKeyRingCollection pgpPublicKeyRing;
+
+    public PGPPublicKeyAccessDefault(byte[] publicKeyRing) throws IOException, PGPException {
+        ObjectHelper.notNull(publicKeyRing, "publicKeyRing");
+        pgpPublicKeyRing = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(new ByteArrayInputStream(publicKeyRing)));
+    }
+
+    @Override
+    public List<PGPPublicKey> getEncryptionKeys(Exchange exchange, List<String> useridParts) throws Exception {
+        return PGPDataFormatUtil.findPublicKeys(useridParts, true, pgpPublicKeyRing);
+    }
+
+    @Override
+    public PGPPublicKey getPublicKey(Exchange exchange, long keyId) throws Exception {
+        return pgpPublicKeyRing.getPublicKey(keyId);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAccess.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAccess.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAccess.java
new file mode 100644
index 0000000..d70a081
--- /dev/null
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAccess.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter.crypto;
+
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.bouncycastle.openpgp.PGPPrivateKey;
+
+public interface PGPSecretKeyAccess {
+
+    /**
+     * Returns the signer keys for the given user ID parts. This method is used
+     * for signing.
+     * 
+     * @param exchange
+     *            exchange, can be <code>null</code>
+     * @param useridParts
+     *            parts of User IDs, can be <code>null</code> or empty, then an
+     *            empty list must be returned
+     * @return list of secret keys with their private keys and User Ids which
+     *         corresponds to one of the useridParts, must not be
+     *         <code>null</code>, can be empty
+     */
+    List<PGPSecretKeyAndPrivateKeyAndUserId> getSignerKeys(Exchange exchange, List<String> useridParts) throws Exception;
+
+    /**
+     * Returns the private key with a certain key ID. This method is used for
+     * decrypting.
+     * 
+     * @param exchange
+     *            exchange, can be <code>null</code>
+     * 
+     * @param keyId
+     *            key ID
+     * @return private key or <code>null</code> if the key cannot be found
+     */
+    PGPPrivateKey getPrivateKey(Exchange exchange, long keyId) throws Exception;
+
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAccessDefault.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAccessDefault.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAccessDefault.java
new file mode 100644
index 0000000..a0c07d7
--- /dev/null
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAccessDefault.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter.crypto;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.util.ObjectHelper;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
+import org.bouncycastle.openpgp.PGPUtil;
+
+/**
+ * Caches a Secret Keyring. Assumes that the password for all private keys is
+ * the same.
+ * 
+ */
+public class PGPSecretKeyAccessDefault implements PGPSecretKeyAccess {
+
+    private final Map<String, List<PGPSecretKeyAndPrivateKeyAndUserId>> userIdPart2SecretKeyList = new HashMap<String, List<PGPSecretKeyAndPrivateKeyAndUserId>>(
+            3);
+
+    private final Map<Long, PGPPrivateKey> keyId2PrivateKey = new HashMap<Long, PGPPrivateKey>(3);
+
+    private final PGPSecretKeyRingCollection pgpSecretKeyring;
+
+    private final String password;
+
+    private final String provider;
+
+    /**
+     * 
+     * @param secretKeyRing
+     *            secret key ring as byte array
+     * @param password
+     *            password for the private keys, assuming that all private keys
+     *            have the same password
+     * @param provider
+     * @throws PGPException
+     * @throws IOException
+     */
+    public PGPSecretKeyAccessDefault(byte[] secretKeyRing, String password, String provider) throws PGPException, IOException {
+        ObjectHelper.notNull(secretKeyRing, "secretKeyRing");
+        ObjectHelper.notEmpty(password, "password");
+        ObjectHelper.notEmpty(provider, "provider");
+        pgpSecretKeyring = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(new ByteArrayInputStream(secretKeyRing)));
+        this.password = password;
+        this.provider = provider;
+    }
+
+    @Override
+    public List<PGPSecretKeyAndPrivateKeyAndUserId> getSignerKeys(Exchange exchange, List<String> useridParts) throws Exception {
+        List<PGPSecretKeyAndPrivateKeyAndUserId> result = new ArrayList<PGPSecretKeyAndPrivateKeyAndUserId>(3);
+        for (String useridPart : useridParts) {
+            List<PGPSecretKeyAndPrivateKeyAndUserId> partResult = userIdPart2SecretKeyList.get(useridPart);
+            if (partResult == null) {
+                partResult = PGPDataFormatUtil.findSecretKeysWithPrivateKeyAndUserId(Collections.singletonMap(useridPart, password),
+                        provider, pgpSecretKeyring);
+                userIdPart2SecretKeyList.put(useridPart, partResult);
+            }
+            result.addAll(partResult);
+        }
+        return result;
+    }
+
+    @Override
+    public PGPPrivateKey getPrivateKey(Exchange exchange, long keyId) throws Exception {
+        Long keyIdLong = Long.valueOf(keyId);
+        PGPPrivateKey result = keyId2PrivateKey.get(keyIdLong);
+        if (result == null) {
+            result = PGPDataFormatUtil.findPrivateKeyWithkeyId(keyId, password, null, provider, pgpSecretKeyring);
+            if (result != null) {
+                keyId2PrivateKey.put(keyIdLong, result);
+            }
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAndPrivateKeyAndUserId.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAndPrivateKeyAndUserId.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAndPrivateKeyAndUserId.java
new file mode 100644
index 0000000..7ab78a8
--- /dev/null
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPSecretKeyAndPrivateKeyAndUserId.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.converter.crypto;
+
+import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+
+/**
+ * Helper class which groups secret, private key and User ID.
+ * 
+ * 
+ */
+public class PGPSecretKeyAndPrivateKeyAndUserId {
+
+    private final PGPSecretKey secretKey;
+
+    private final PGPPrivateKey privateKey;
+
+    private final String userId;
+
+    public PGPSecretKeyAndPrivateKeyAndUserId(PGPSecretKey secretKey, PGPPrivateKey privateKey, String userId) {
+        this.secretKey = secretKey;
+        this.privateKey = privateKey;
+        this.userId = userId;
+    }
+
+    public PGPSecretKey getSecretKey() {
+        return secretKey;
+    }
+
+    public PGPPrivateKey getPrivateKey() {
+        return privateKey;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/62c8b7ad/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java b/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java
index 1aa7f7f..ab4a1b1 100644
--- a/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java
+++ b/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/PGPDataFormatTest.java
@@ -129,6 +129,11 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
     }
 
     @Test
+    public void testKeyAccess() throws Exception {
+        doRoundTripEncryptionTests("direct:key_access");
+    }
+
+    @Test
     public void testVerifyExceptionNoPublicKeyFoundCorrespondingToSignatureUserIds() throws Exception {
         setupExpectations(context, 1, "mock:encrypted");
         MockEndpoint exception = setupExpectations(context, 1, "mock:exception");
@@ -390,6 +395,28 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
 
                 from("direct:keyflag").marshal(pgpKeyFlag).to("mock:encrypted_keyflag");
             }
+        }, new RouteBuilder() {
+            public void configure() throws Exception {
+
+                PGPPublicKeyAccess publicKeyAccess = new PGPPublicKeyAccessDefault(getPublicKeyRing());
+                //password cannot be set dynamically!
+                PGPSecretKeyAccess secretKeyAccess = new PGPSecretKeyAccessDefault(getSecKeyRing(), "sdude", getProvider());
+
+                PGPKeyAccessDataFormat dfEncryptSignKeyAccess = new PGPKeyAccessDataFormat();
+                dfEncryptSignKeyAccess.setPublicKeyAccess(publicKeyAccess);
+                dfEncryptSignKeyAccess.setSecretKeyAccess(secretKeyAccess);
+                dfEncryptSignKeyAccess.setKeyUserid(getKeyUserId());
+                dfEncryptSignKeyAccess.setSignatureKeyUserid(getKeyUserId());
+
+                PGPKeyAccessDataFormat dfDecryptVerifyKeyAccess = new PGPKeyAccessDataFormat();
+                dfDecryptVerifyKeyAccess.setPublicKeyAccess(publicKeyAccess);
+                dfDecryptVerifyKeyAccess.setSecretKeyAccess(secretKeyAccess);
+                dfDecryptVerifyKeyAccess.setSignatureKeyUserid(getKeyUserId());
+
+                from("direct:key_access").marshal(dfEncryptSignKeyAccess).to("mock:encrypted").unmarshal(dfDecryptVerifyKeyAccess)
+                        .to("mock:unencrypted");
+
+            }
         } };
     }