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 2013/10/21 12:09:04 UTC

git commit: CAMEL-6875 Added PGPPassphraseAccessor to support more sophsiticate keyring with thanks to Franz

Updated Branches:
  refs/heads/master 43817b29d -> dabc2dbaa


CAMEL-6875 Added PGPPassphraseAccessor to support more sophsiticate keyring 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/dabc2dba
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/dabc2dba
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/dabc2dba

Branch: refs/heads/master
Commit: dabc2dbaa006741eacc2e4a7aa389c3975ff8823
Parents: 43817b2
Author: Willem Jiang <ni...@apache.org>
Authored: Mon Oct 21 18:05:02 2013 +0800
Committer: Willem Jiang <ni...@apache.org>
Committed: Mon Oct 21 18:05:02 2013 +0800

----------------------------------------------------------------------
 .../camel/converter/crypto/PGPDataFormat.java   | 122 ++++++++++----
 .../converter/crypto/PGPDataFormatUtil.java     | 163 ++++++++++++++++---
 .../converter/crypto/PGPPassphraseAccessor.java |  34 ++++
 .../crypto/PGPPassphraseAccessorDefault.java    |  54 ++++++
 .../converter/crypto/PGPDataFormatTest.java     |  28 ++--
 .../crypto/SpringPGPDataFormatTest.xml          |  16 +-
 .../apache/camel/component/crypto/pubring.gpg   | Bin 1184 -> 2814 bytes
 .../apache/camel/component/crypto/secring.gpg   | Bin 2562 -> 5570 bytes
 8 files changed, 343 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/dabc2dba/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 e6d8921..c14c5c8 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
@@ -111,20 +111,30 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
 
     private boolean armored;
     private boolean integrity = true;
-    
-    /** Digest algorithm for signing (marshal).
-     * Possible values are defined in {@link HashAlgorithmTags}.
-     * Default value is SHA1.
+
+    /**
+     * Digest algorithm for signing (marshal). Possible values are defined in
+     * {@link HashAlgorithmTags}. Default value is SHA1.
      */
     private int hashAlgorithm = HashAlgorithmTags.SHA1;
-    
+
     /**
-     * Symmetric key algorithm for encryption (marschal).
-     * Possible values are defined in {@link SymmetricKeyAlgorithmTags}.
-     * Default value is CAST5.
+     * Symmetric key algorithm for encryption (marschal). Possible values are
+     * defined in {@link SymmetricKeyAlgorithmTags}. Default value is CAST5.
      */
     private int algorithm = SymmetricKeyAlgorithmTags.CAST5;
 
+    /**
+     * If no passpharase can be found from the parameter <tt>password</tt> or
+     * <tt>signaturePassword</tt> or from the header
+     * {@link #SIGNATURE_KEY_PASSWORD} or {@link #KEY_PASSWORD} then we try to
+     * get the password from the passphrase accessor. This is especially useful
+     * in the decrypt case, where we chose the private key according to the key
+     * Id stored in the encrypted data. So in this case we do not know the user
+     * Id in advance.
+     */
+    private PGPPassphraseAccessor passphraseAccessor;
+
     public PGPDataFormat() {
     }
 
@@ -141,7 +151,15 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
     }
 
     protected String findKeyPassword(Exchange exchange) {
-        return exchange.getIn().getHeader(KEY_PASSWORD, getPassword(), String.class);
+        String keyPassword = exchange.getIn().getHeader(KEY_PASSWORD, getPassword(), String.class);
+        if (keyPassword != null) {
+            return keyPassword;
+        }
+        if (passphraseAccessor != null) {
+            return passphraseAccessor.getPassphrase(findKeyUserid(exchange));
+        } else {
+            return null;
+        }
     }
 
     protected String findSignatureKeyFileName(Exchange exchange) {
@@ -157,9 +175,17 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
     }
 
     protected String findSignatureKeyPassword(Exchange exchange) {
-        return exchange.getIn().getHeader(SIGNATURE_KEY_PASSWORD, getSignaturePassword(), String.class);
+        String sigPassword = exchange.getIn().getHeader(SIGNATURE_KEY_PASSWORD, getSignaturePassword(), String.class);
+        if (sigPassword != null) {
+            return sigPassword;
+        }
+        if (passphraseAccessor != null) {
+            return passphraseAccessor.getPassphrase(findSignatureKeyUserid(exchange));
+        } else {
+            return null;
+        }
     }
-    
+
     protected int findAlgorithm(Exchange exchange) {
         return exchange.getIn().getHeader(ENCRYPTION_ALGORITHM, getAlgorithm(), Integer.class);
     }
@@ -231,13 +257,14 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
             return null;
         }
 
-        PGPSecretKey sigSecretKey = PGPDataFormatUtil.findSecretKey(exchange.getContext(), sigKeyFileName, sigKeyRing, sigKeyPassword, getProvider());
+        PGPSecretKey sigSecretKey = PGPDataFormatUtil.findSecretKey(exchange.getContext(), sigKeyFileName, sigKeyRing, sigKeyPassword,
+                sigKeyUserid, getProvider());
         if (sigSecretKey == null) {
             throw new IllegalArgumentException("Signature secret key is null, cannot proceed");
         }
 
-        PGPPrivateKey sigPrivateKey = sigSecretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(getProvider()).build(
-                sigKeyPassword.toCharArray()));
+        PGPPrivateKey sigPrivateKey = sigSecretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(getProvider())
+                .build(sigKeyPassword.toCharArray()));
         if (sigPrivateKey == null) {
             throw new IllegalArgumentException("Signature private key is null, cannot proceed");
         }
@@ -259,15 +286,10 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
             return null;
         }
 
-        PGPPrivateKey key = PGPDataFormatUtil.findPrivateKey(exchange.getContext(), findKeyFileName(exchange),
-                findEncryptionKeyRing(exchange), encryptedStream, findKeyPassword(exchange), getProvider());
-        if (key == null) {
-            throw new IllegalArgumentException("Private key is null, cannot proceed");
-        }
-
         InputStream in;
         try {
             byte[] encryptedData = IOUtils.toByteArray(encryptedStream);
+            //TODO why do we need a byte array input stream? --> streaming not possible?
             InputStream byteStream = new ByteArrayInputStream(encryptedData);
             in = PGPUtil.getDecoderStream(byteStream);
         } finally {
@@ -286,11 +308,21 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         }
         IOHelper.close(in);
 
-        PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) enc.get(0);
+        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) {
+            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();
 
@@ -305,6 +337,7 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         PGPLiteralData ld = (PGPLiteralData) object;
         InputStream litData = ld.getInputStream();
 
+        //TODO we should enable streaming here with CashedOutputStream!!
         byte[] answer;
         try {
             answer = Streams.readAll(litData);
@@ -315,7 +348,7 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         if (signature != null) {
             signature.update(answer);
             PGPSignatureList sigList = (PGPSignatureList) pgpFactory.nextObject();
-            if (!signature.verify(sigList.get(0))) {
+            if (!signature.verify(getSignatureWithKeyId(signature.getKeyID(), sigList))) {
                 throw new SignatureException("Cannot verify PGP signature");
             }
         }
@@ -323,18 +356,37 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         return answer;
     }
 
+    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 {
 
-        PGPPublicKey sigPublicKey = PGPDataFormatUtil.findPublicKey(exchange.getContext(), findSignatureKeyFileName(exchange),
-                findSignatureKeyRing(exchange), findSignatureKeyUserid(exchange), false);
-        if (sigPublicKey == null) {
-            throw new IllegalArgumentException("Signature public key is null, cannot proceed");
+        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;
+            }
+            // 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");
         }
 
-        PGPOnePassSignature signature = signatureList.get(0);
-        signature.init(new JcaPGPContentVerifierBuilderProvider().setProvider(getProvider()), sigPublicKey);
-        return signature;
     }
 
     /**
@@ -448,8 +500,6 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
     public void setProvider(String provider) {
         this.provider = provider;
     }
-    
-    
 
     public int getHashAlgorithm() {
         return hashAlgorithm;
@@ -467,6 +517,14 @@ public class PGPDataFormat extends ServiceSupport implements DataFormat {
         this.algorithm = algorithm;
     }
 
+    public PGPPassphraseAccessor getPassphraseAccessor() {
+        return passphraseAccessor;
+    }
+
+    public void setPassphraseAccessor(PGPPassphraseAccessor passphraseAccessor) {
+        this.passphraseAccessor = passphraseAccessor;
+    }
+
     @Override
     protected void doStart() throws Exception {
         if (Security.getProvider(BC) == null && BC.equals(getProvider())) {

http://git-wip-us.apache.org/repos/asf/camel/blob/dabc2dba/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 1dfa33a..bff00ad 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
@@ -50,8 +50,9 @@ public final class PGPDataFormatUtil {
     private PGPDataFormatUtil() {
     }
 
-    public static PGPPublicKey findPublicKey(CamelContext context, String filename, String userid, boolean forEncryption) throws IOException, PGPException,
-            NoSuchProviderException {
+    @Deprecated
+    public static PGPPublicKey findPublicKey(CamelContext context, String filename, String userid, boolean forEncryption)
+        throws IOException, PGPException, NoSuchProviderException {
         return findPublicKey(context, filename, null, userid, forEncryption);
     }
 
@@ -68,6 +69,57 @@ public final class PGPDataFormatUtil {
         return pubKey;
     }
 
+    public static PGPPublicKey findPublicKeyWithKeyId(CamelContext context, String filename, byte[] keyRing, long keyid,
+            boolean forEncryption) throws IOException, PGPException, NoSuchProviderException {
+        InputStream is = determineKeyRingInputStream(context, filename, keyRing, forEncryption);
+        PGPPublicKey pubKey;
+        try {
+            pubKey = findPublicKeyWithKeyId(is, keyid);
+        } finally {
+            IOHelper.close(is);
+        }
+        return pubKey;
+    }
+
+    public static PGPPrivateKey findPrivateKeyWithKeyId(CamelContext context, String filename, byte[] secreteKeyRing, long keyid,
+            String passphrase, PGPPassphraseAccessor passpraseAccessor, String provider) throws IOException, PGPException,
+            NoSuchProviderException {
+        InputStream is = determineKeyRingInputStream(context, filename, secreteKeyRing, true);
+        try {
+            return findPrivateKeyWithKeyId(is, keyid, passphrase, passpraseAccessor, provider);
+        } finally {
+            IOHelper.close(is);
+        }
+    }
+
+    private static PGPPrivateKey findPrivateKeyWithKeyId(InputStream keyringInput, long keyid, String passphrase,
+            PGPPassphraseAccessor passphraseAccessor, String provider) throws IOException, PGPException {
+        PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyringInput));
+        for (Iterator<?> i = pgpSec.getKeyRings(); i.hasNext();) {
+            Object data = i.next();
+            if (data instanceof PGPSecretKeyRing) {
+                PGPSecretKeyRing keyring = (PGPSecretKeyRing) data;
+                PGPSecretKey secKey = keyring.getSecretKey();
+                if (secKey != null && keyid == secKey.getKeyID()) {
+                    if (passphrase == null && passphraseAccessor != null) {
+                        // get passphrase from accessor
+                        @SuppressWarnings("unchecked")
+                        Iterator<String> userIDs = secKey.getUserIDs();
+                        while (passphrase == null && userIDs.hasNext()) {
+                            passphrase = passphraseAccessor.getPassphrase(userIDs.next());
+                        }
+                    }
+                    PGPPrivateKey privateKey = secKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(
+                            passphrase.toCharArray()));
+                    if (privateKey != null) {
+                        return privateKey;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
     private static InputStream determineKeyRingInputStream(CamelContext context, String filename, byte[] keyRing, boolean forEncryption)
         throws IOException {
         if (filename != null && keyRing != null) {
@@ -90,6 +142,24 @@ public final class PGPDataFormatUtil {
     }
 
     @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();
+            for (Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys(); keyIter.hasNext();) {
+                PGPPublicKey key = keyIter.next();
+                if (keyid == key.getKeyID()) {
+                    return key;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
     private static PGPPublicKey findPublicKey(InputStream input, String userid, boolean forEncryption) throws IOException, PGPException,
             NoSuchProviderException {
         PGPPublicKeyRingCollection pgpSec = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input));
@@ -99,17 +169,17 @@ public final class PGPDataFormatUtil {
             PGPPublicKeyRing keyRing = keyRingIter.next();
 
             Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys();
-            String keyUserId = null;
             while (keyIter.hasNext()) {
                 PGPPublicKey key = keyIter.next();
                 for (Iterator<String> iterator = key.getUserIDs(); iterator.hasNext();) {
-                    keyUserId = iterator.next();
-                }
-                if (keyUserId != null && keyUserId.contains(userid)) {
-                    if (forEncryption && key.isEncryptionKey()) {
-                        return key;
-                    } else if (!forEncryption && isSignatureKey(key)) {
-                        return key;
+                    String keyUserId = iterator.next();
+                    // there can be serveral user IDs!
+                    if (keyUserId != null && keyUserId.contains(userid)) {
+                        if (forEncryption && key.isEncryptionKey()) {
+                            return key;
+                        } else if (!forEncryption && isSignatureKey(key)) {
+                            return key;
+                        }
                     }
                 }
             }
@@ -123,26 +193,36 @@ public final class PGPDataFormatUtil {
         return algorithm == RSA_GENERAL || algorithm == RSA_SIGN || algorithm == DSA || algorithm == ECDSA || algorithm == ELGAMAL_GENERAL;
     }
 
+    @Deprecated
     public static PGPPrivateKey findPrivateKey(CamelContext context, String keychainFilename, InputStream encryptedInput, String passphrase)
         throws IOException, PGPException, NoSuchProviderException {
         return findPrivateKey(context, keychainFilename, null, encryptedInput, passphrase, "BC");
     }
 
+    @Deprecated
     public static PGPPrivateKey findPrivateKey(CamelContext context, String keychainFilename, byte[] secKeyRing,
-        InputStream encryptedInput, String passphrase, String provider) throws IOException, PGPException, NoSuchProviderException {
+            InputStream encryptedInput, String passphrase, String provider) throws IOException, PGPException, NoSuchProviderException {
+        return findPrivateKey(context, keychainFilename, secKeyRing, encryptedInput, passphrase, null, provider);
+    }
+
+    @Deprecated
+    public static PGPPrivateKey findPrivateKey(CamelContext context, String keychainFilename, byte[] secKeyRing,
+            InputStream encryptedInput, String passphrase, PGPPassphraseAccessor passphraseAccessor, String provider) throws IOException,
+            PGPException, NoSuchProviderException {
 
         InputStream keyChainInputStream = determineKeyRingInputStream(context, keychainFilename, secKeyRing, true);
         PGPPrivateKey privKey = null;
         try {
-            privKey = findPrivateKey(keyChainInputStream, encryptedInput, passphrase, provider);
+            privKey = findPrivateKey(keyChainInputStream, encryptedInput, passphrase, passphraseAccessor, provider);
         } finally {
             IOHelper.close(keyChainInputStream);
         }
         return privKey;
     }
 
-    private static PGPPrivateKey findPrivateKey(InputStream keyringInput, InputStream encryptedInput, String passphrase, String provider) throws IOException,
-            PGPException, NoSuchProviderException {
+    @Deprecated
+    private static PGPPrivateKey findPrivateKey(InputStream keyringInput, InputStream encryptedInput, String passphrase,
+            PGPPassphraseAccessor passphraseAccessor, String provider) throws IOException, PGPException, NoSuchProviderException {
         PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyringInput));
         PGPObjectFactory factory = new PGPObjectFactory(PGPUtil.getDecoderStream(encryptedInput));
         PGPEncryptedDataList enc;
@@ -163,7 +243,16 @@ public final class PGPDataFormatUtil {
             encryptedData = (PGPPublicKeyEncryptedData) encryptedDataObjects.next();
             PGPSecretKey pgpSecKey = pgpSec.getSecretKey(encryptedData.getKeyID());
             if (pgpSecKey != null) {
-                privateKey = pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(passphrase.toCharArray()));
+                if (passphrase == null && passphraseAccessor != null) {
+                    // get passphrase from accessor
+                    @SuppressWarnings("unchecked")
+                    Iterator<String> userIDs = pgpSecKey.getUserIDs();
+                    while (passphrase == null && userIDs.hasNext()) {
+                        passphrase = passphraseAccessor.getPassphrase(userIDs.next());
+                    }
+                }
+                privateKey = pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(
+                        passphrase.toCharArray()));
             }
         }
         if (privateKey == null && pgpSec.size() > 0 && encryptedData != null) {
@@ -172,25 +261,34 @@ public final class PGPDataFormatUtil {
         return privateKey;
     }
 
-    public static PGPSecretKey findSecretKey(CamelContext context, String keychainFilename, String passphrase)
-        throws IOException, PGPException, NoSuchProviderException {
+    @Deprecated
+    public static PGPSecretKey findSecretKey(CamelContext context, String keychainFilename, String passphrase) throws IOException,
+            PGPException, NoSuchProviderException {
         return findSecretKey(context, keychainFilename, null, passphrase, "BC");
     }
 
-    public static PGPSecretKey findSecretKey(CamelContext context, String keychainFilename, byte[] secKeyRing, String passphrase, String provider)
-        throws IOException, PGPException, NoSuchProviderException {
-
+    public static PGPSecretKey findSecretKey(CamelContext context, String keychainFilename, byte[] secKeyRing, String passphrase,
+            String userId, String provider) throws IOException, PGPException, NoSuchProviderException {
         InputStream keyChainInputStream = determineKeyRingInputStream(context, keychainFilename, secKeyRing, false);
         PGPSecretKey secKey = null;
         try {
-            secKey = findSecretKey(keyChainInputStream, passphrase, provider);
+            secKey = findSecretKey(keyChainInputStream, passphrase, userId, provider);
         } finally {
             IOHelper.close(keyChainInputStream);
         }
         return secKey;
     }
 
-    private static PGPSecretKey findSecretKey(InputStream keyringInput, String passphrase, String provider) throws IOException, PGPException, NoSuchProviderException {
+    @Deprecated
+    public static PGPSecretKey findSecretKey(CamelContext context, String keychainFilename, byte[] secKeyRing, String passphrase,
+            String provider) throws IOException, PGPException, NoSuchProviderException {
+
+        return findSecretKey(context, keychainFilename, secKeyRing, passphrase, null, provider);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static PGPSecretKey findSecretKey(InputStream keyringInput, String passphrase, String userId, String provider)
+        throws IOException, PGPException, NoSuchProviderException {
         PGPSecretKey pgpSecKey = null;
         PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyringInput));
         for (Iterator<?> i = pgpSec.getKeyRings(); i.hasNext() && pgpSecKey == null;) {
@@ -198,9 +296,24 @@ public final class PGPDataFormatUtil {
             if (data instanceof PGPSecretKeyRing) {
                 PGPSecretKeyRing keyring = (PGPSecretKeyRing) data;
                 PGPSecretKey secKey = keyring.getSecretKey();
-                PGPPrivateKey privateKey = secKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(passphrase.toCharArray()));
-                if (privateKey != null) {
-                    pgpSecKey = secKey;
+                if (userId != null) {
+                    for (Iterator<String> iterator = secKey.getUserIDs(); iterator.hasNext();) {
+                        String keyUserId = iterator.next();
+                        // there can be serveral user IDs!
+                        if (keyUserId != null && keyUserId.contains(userId)) {
+                            PGPPrivateKey privateKey = secKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(provider)
+                                    .build(passphrase.toCharArray()));
+                            if (privateKey != null) {
+                                return secKey;
+                            }
+                        }
+                    }
+                } else {
+                    PGPPrivateKey privateKey = secKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(
+                            passphrase.toCharArray()));
+                    if (privateKey != null) {
+                        pgpSecKey = secKey;
+                    }
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/camel/blob/dabc2dba/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPassphraseAccessor.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPassphraseAccessor.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPassphraseAccessor.java
new file mode 100644
index 0000000..4bd6b8f
--- /dev/null
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPassphraseAccessor.java
@@ -0,0 +1,34 @@
+/**
+ * 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;
+
+/**
+ * Access to the password for a user Id.
+ * 
+ */
+public interface PGPPassphraseAccessor {
+
+    /**
+     * Returns the passphrase for a user Id
+     * 
+     * @param userId
+     *            user Id, can be <code>null</code>
+     * @return the passphrase for the user Id, or <code>null</code> if the
+     *         passphrase cannot be found
+     */
+    String getPassphrase(String userId);
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/dabc2dba/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPassphraseAccessorDefault.java
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPassphraseAccessorDefault.java b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPassphraseAccessorDefault.java
new file mode 100644
index 0000000..6796ccd
--- /dev/null
+++ b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/PGPPassphraseAccessorDefault.java
@@ -0,0 +1,54 @@
+/**
+ * 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.Map;
+
+/**
+ * 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.
+ */
+import org.apache.camel.util.ObjectHelper;
+
+public class PGPPassphraseAccessorDefault implements PGPPassphraseAccessor {
+
+    private final Map<String, String> userId2Passphrase;
+
+    public PGPPassphraseAccessorDefault(Map<String, String> userId2Passphrase) {
+        ObjectHelper.notNull(userId2Passphrase, "userIdPassphrase");
+
+        this.userId2Passphrase = userId2Passphrase;
+    }
+
+    @Override
+    public String getPassphrase(String userId) {
+        return userId2Passphrase.get(userId);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/dabc2dba/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 e890d53..a739a42 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
@@ -19,6 +19,8 @@ package org.apache.camel.converter.crypto;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
 
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.util.IOHelper;
@@ -106,7 +108,7 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
                 from("direct:inline")
                         .marshal().pgp(keyFileName, keyUserid)
                         .to("mock:encrypted")
-                        .unmarshal().pgp(keyFileNameSec, keyUserid, keyPassword)
+                        .unmarshal().pgp(keyFileNameSec, null, keyPassword)
                         .to("mock:unencrypted");
                 // END SNIPPET: pgp-format
 
@@ -119,7 +121,7 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
 
                 PGPDataFormat pgpDecrypt = new PGPDataFormat();
                 pgpDecrypt.setKeyFileName(keyFileNameSec);
-                pgpDecrypt.setKeyUserid(keyUserid);
+               // pgpDecrypt.setKeyUserid(keyUserid);
                 pgpDecrypt.setPassword(keyPassword);
                 pgpDecrypt.setProvider(getProvider());
 
@@ -132,7 +134,7 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
                 from("direct:inline-armor")
                         .marshal().pgp(keyFileName, keyUserid, null, true, true)
                         .to("mock:encrypted")
-                        .unmarshal().pgp(keyFileNameSec, keyUserid, keyPassword, true, true)
+                        .unmarshal().pgp(keyFileNameSec, null, keyPassword, true, true)
                         .to("mock:unencrypted");
                 // END SNIPPET: pgp-format-header
 
@@ -141,8 +143,9 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
                 pgpSignAndEncrypt.setKeyFileName(keyFileName);
                 pgpSignAndEncrypt.setKeyUserid(keyUserid);
                 pgpSignAndEncrypt.setSignatureKeyFileName(keyFileNameSec);
+                PGPPassphraseAccessor passphraseAccessor = getPassphraseAccessor();
                 pgpSignAndEncrypt.setSignatureKeyUserid(keyUserid);
-                pgpSignAndEncrypt.setSignaturePassword(keyPassword);
+                pgpSignAndEncrypt.setPassphraseAccessor(passphraseAccessor);
                 pgpSignAndEncrypt.setProvider(getProvider());
                 pgpSignAndEncrypt.setAlgorithm(getAlgorithm());
                 pgpSignAndEncrypt.setHashAlgorithm(getHashAlgorithm());
@@ -150,10 +153,8 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
 
                 PGPDataFormat pgpVerifyAndDecrypt = new PGPDataFormat();
                 pgpVerifyAndDecrypt.setKeyFileName(keyFileNameSec);
-                pgpVerifyAndDecrypt.setKeyUserid(keyUserid);
                 pgpVerifyAndDecrypt.setPassword(keyPassword);
                 pgpVerifyAndDecrypt.setSignatureKeyFileName(keyFileName);
-                pgpVerifyAndDecrypt.setSignatureKeyUserid(keyUserid);
                 pgpVerifyAndDecrypt.setProvider(getProvider());
 
                 from("direct:inline-sign")
@@ -172,8 +173,7 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
 
                 PGPDataFormat pgpDecryptByteArray = new PGPDataFormat();
                 pgpDecryptByteArray.setEncryptionKeyRing(getSecKeyRing());
-                pgpDecryptByteArray.setKeyUserid(keyUserid);
-                pgpDecryptByteArray.setPassword(keyPassword);
+                pgpDecryptByteArray.setPassphraseAccessor(passphraseAccessor);
                 pgpDecryptByteArray.setProvider(getProvider());
 
                 from("direct:key-ring-byte-array").marshal(pgpEncryptByteArray).to("mock:encrypted").unmarshal(pgpDecryptByteArray)
@@ -191,10 +191,8 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
                 pgpSignAndEncryptByteArray.setHashAlgorithm(HashAlgorithmTags.RIPEMD160);
 
                 PGPDataFormat pgpVerifyAndDecryptByteArray = new PGPDataFormat();
-                pgpVerifyAndDecryptByteArray.setKeyUserid(keyUserid);
-                pgpVerifyAndDecryptByteArray.setPassword(keyPassword);
+                pgpVerifyAndDecryptByteArray.setPassphraseAccessor(passphraseAccessor);
                 pgpVerifyAndDecryptByteArray.setEncryptionKeyRing(getSecKeyRing());
-                pgpVerifyAndDecryptByteArray.setSignatureKeyUserid(keyUserid);
                 pgpVerifyAndDecryptByteArray.setProvider(getProvider());
 
                 from("direct:sign-key-ring-byte-array")
@@ -208,6 +206,8 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
                         .removeHeader(PGPDataFormat.SIGNATURE_KEY_RING).to("mock:unencrypted");
                 // END SNIPPET: pgp-format-signature-key-ring-byte-array
             }
+
+           
         };
     }
 
@@ -226,5 +226,11 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest {
         output.close();
         return output.toByteArray();
     }
+    
+    public static PGPPassphraseAccessor getPassphraseAccessor() {
+        Map<String, String> userId2Passphrase = Collections.singletonMap("Super <sd...@nowhere.net>", "sdude");
+        PGPPassphraseAccessor passphraseAccessor = new PGPPassphraseAccessorDefault(userId2Passphrase);
+        return passphraseAccessor;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/dabc2dba/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/SpringPGPDataFormatTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/SpringPGPDataFormatTest.xml b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/SpringPGPDataFormatTest.xml
index 38d8c39..fcc15ac 100644
--- a/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/SpringPGPDataFormatTest.xml
+++ b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/SpringPGPDataFormatTest.xml
@@ -28,7 +28,7 @@
       <pgp id="encrypt" keyFileName="org/apache/camel/component/crypto/pubring.gpg"
            keyUserid="sdude@nowhere.net"/>
       <pgp id="decrypt" keyFileName="org/apache/camel/component/crypto/secring.gpg"
-           keyUserid="sdude@nowhere.net" password="sdude"/>
+           password="sdude"/>
     </dataFormats>
 
     <route>
@@ -56,20 +56,24 @@
       <property name="algorithm" value="7"/> <!-- AES128  algorithm -->
    </bean>
    
-   <bean id="decryptBean" class="org.apache.camel.converter.crypto.PGPDataFormat">
-      <property name="keyUserid" value="sdude@nowhere.net"/>  
+   <bean id="decryptBean" class="org.apache.camel.converter.crypto.PGPDataFormat"> 
       <property name="encryptionKeyRing" ref="secKeyRing"/>
-      <property name="password" value="sdude"/>
+      <property name="passphraseAccessor" ref="passphraseAccessorBean"/>
    </bean>
    
-   <!-- bean represents the publik key ring as byte array -->
+   <!-- bean represents the public key ring as byte array -->
    <bean id="pubKeyRing"
 		class="org.apache.camel.converter.crypto.PGPDataFormatTest"
 		factory-method="getPublicKeyRing" />
 		
-	<!-- bean represents the secure key ring as byte array -->	
+	<!-- bean represents the secret key ring as byte array -->	
    <bean id="secKeyRing"
 		class="org.apache.camel.converter.crypto.PGPDataFormatTest"
 		factory-method="getSecKeyRing" />
+        
+    <!-- bean passphrase accessor  -->
+     <bean id="passphraseAccessorBean"
+        class="org.apache.camel.converter.crypto.PGPDataFormatTest"
+        factory-method="getPassphraseAccessor" />
     <!-- END SNIPPET:  pgp-xml-data-format-bean-with-keyring-bytearray -->
 </beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/dabc2dba/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubring.gpg
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubring.gpg b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubring.gpg
index 4b3e405..21029c6 100644
Binary files a/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubring.gpg and b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/pubring.gpg differ

http://git-wip-us.apache.org/repos/asf/camel/blob/dabc2dba/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secring.gpg
----------------------------------------------------------------------
diff --git a/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secring.gpg b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secring.gpg
index d631be3..36af553 100644
Binary files a/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secring.gpg and b/components/camel-crypto/src/test/resources/org/apache/camel/component/crypto/secring.gpg differ