CAMEL-6742 PGP Data Format: enable configuration of public and secure key ring via byte array parameter 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/e4a81eac Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e4a81eac Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e4a81eac Branch: refs/heads/camel-2.12.x Commit: e4a81eac727b6ca51149fb0a1d604a3816d2179a Parents: c57359a Author: Willem Jiang <[email protected]> Authored: Fri Sep 13 16:27:32 2013 +0800 Committer: Willem Jiang <[email protected]> Committed: Fri Sep 13 16:28:40 2013 +0800 ---------------------------------------------------------------------- .../camel/converter/crypto/PGPDataFormat.java | 54 +++++++++++--- .../converter/crypto/PGPDataFormatUtil.java | 43 ++++++++++- .../converter/crypto/PGPDataFormatTest.java | 77 +++++++++++++++++++- .../crypto/SpringPGPDataFormatTest.java | 5 ++ .../crypto/SpringPGPDataFormatTest.xml | 31 +++++++- 5 files changed, 193 insertions(+), 17 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/e4a81eac/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 df13927..d0d3730 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 @@ -73,9 +73,11 @@ import org.bouncycastle.util.io.Streams; public class PGPDataFormat implements DataFormat { 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_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_PASSWORD = "CamelPGPDataFormatSignatureKeyPassword"; @@ -85,11 +87,15 @@ public class PGPDataFormat implements DataFormat { private String keyUserid; private String password; 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; private String signaturePassword; private String signatureKeyFileName; + // alternatively to the sigknature key file name you can specify the signature key ring as byte array + private byte[] signatureKeyRing; private boolean armored; private boolean integrity = true; @@ -101,31 +107,39 @@ public class PGPDataFormat implements DataFormat { } protected String findKeyFileName(Exchange exchange) { - return exchange.getIn().getHeader(KEY_FILE_NAME, keyFileName, String.class); + return exchange.getIn().getHeader(KEY_FILE_NAME, getKeyFileName(), String.class); + } + + protected byte[] findEncryptionKeyRing(Exchange exchange) { + return exchange.getIn().getHeader(ENCRYPTION_KEY_RING, getEncryptionKeyRing(), byte[].class); } protected String findKeyUserid(Exchange exchange) { - return exchange.getIn().getHeader(KEY_USERID, keyUserid, String.class); + return exchange.getIn().getHeader(KEY_USERID, getKeyUserid(), String.class); } protected String findKeyPassword(Exchange exchange) { - return exchange.getIn().getHeader(KEY_PASSWORD, password, String.class); + return exchange.getIn().getHeader(KEY_PASSWORD, getPassword(), String.class); } protected String findSignatureKeyFileName(Exchange exchange) { - return exchange.getIn().getHeader(SIGNATURE_KEY_FILE_NAME, signatureKeyFileName, String.class); + return exchange.getIn().getHeader(SIGNATURE_KEY_FILE_NAME, getSignatureKeyFileName(), String.class); + } + + protected byte[] findSignatureKeyRing(Exchange exchange) { + return exchange.getIn().getHeader(SIGNATURE_KEY_RING, getSignatureKeyRing(), byte[].class); } protected String findSignatureKeyUserid(Exchange exchange) { - return exchange.getIn().getHeader(SIGNATURE_KEY_USERID, signatureKeyUserid, String.class); + return exchange.getIn().getHeader(SIGNATURE_KEY_USERID, getSignatureKeyUserid(), String.class); } protected String findSignatureKeyPassword(Exchange exchange) { - return exchange.getIn().getHeader(SIGNATURE_KEY_PASSWORD, signaturePassword, String.class); + return exchange.getIn().getHeader(SIGNATURE_KEY_PASSWORD, getSignaturePassword(), String.class); } public void marshal(Exchange exchange, Object graph, OutputStream outputStream) throws Exception { - PGPPublicKey key = PGPDataFormatUtil.findPublicKey(exchange.getContext(), findKeyFileName(exchange), findKeyUserid(exchange), true); + PGPPublicKey key = PGPDataFormatUtil.findPublicKey(exchange.getContext(), findKeyFileName(exchange), findEncryptionKeyRing(exchange), findKeyUserid(exchange), true); if (key == null) { throw new IllegalArgumentException("Public key is null, cannot proceed"); } @@ -182,12 +196,13 @@ public class PGPDataFormat implements DataFormat { String sigKeyFileName = findSignatureKeyFileName(exchange); String sigKeyUserid = findSignatureKeyUserid(exchange); String sigKeyPassword = findSignatureKeyPassword(exchange); + byte[] sigKeyRing = findSignatureKeyRing(exchange); - if (sigKeyFileName == null || sigKeyUserid == null || sigKeyPassword == null) { + if ((sigKeyFileName == null && sigKeyRing == null) || sigKeyUserid == null || sigKeyPassword == null) { return null; } - PGPSecretKey sigSecretKey = PGPDataFormatUtil.findSecretKey(exchange.getContext(), sigKeyFileName, sigKeyPassword); + PGPSecretKey sigSecretKey = PGPDataFormatUtil.findSecretKey(exchange.getContext(), sigKeyFileName, sigKeyRing, sigKeyPassword); if (sigSecretKey == null) { throw new IllegalArgumentException("Signature secret key is null, cannot proceed"); } @@ -213,7 +228,7 @@ public class PGPDataFormat implements DataFormat { return null; } - PGPPrivateKey key = PGPDataFormatUtil.findPrivateKey(exchange.getContext(), findKeyFileName(exchange), encryptedStream, findKeyPassword(exchange)); + PGPPrivateKey key = PGPDataFormatUtil.findPrivateKey(exchange.getContext(), findKeyFileName(exchange), findEncryptionKeyRing(exchange), encryptedStream, findKeyPassword(exchange)); if (key == null) { throw new IllegalArgumentException("Private key is null, cannot proceed"); } @@ -279,7 +294,7 @@ public class PGPDataFormat implements DataFormat { protected PGPOnePassSignature getSignature(Exchange exchange, PGPOnePassSignatureList signatureList) throws IOException, PGPException, NoSuchProviderException { - PGPPublicKey sigPublicKey = PGPDataFormatUtil.findPublicKey(exchange.getContext(), findSignatureKeyFileName(exchange), findSignatureKeyUserid(exchange), false); + 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"); } @@ -376,4 +391,21 @@ public class PGPDataFormat implements DataFormat { public String getSignaturePassword() { return signaturePassword; } + + public byte[] getEncryptionKeyRing() { + return encryptionKeyRing; + } + + public void setEncryptionKeyRing(byte[] encryptionKeyRing) { + this.encryptionKeyRing = encryptionKeyRing; + } + + public byte[] getSignatureKeyRing() { + return signatureKeyRing; + } + + public void setSignatureKeyRing(byte[] signatureKeyRing) { + this.signatureKeyRing = signatureKeyRing; + } + } http://git-wip-us.apache.org/repos/asf/camel/blob/e4a81eac/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 f01724d..0916075 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,9 @@ */ package org.apache.camel.converter.crypto; + + +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.security.NoSuchProviderException; @@ -51,8 +54,13 @@ public final class PGPDataFormatUtil { public static PGPPublicKey findPublicKey(CamelContext context, String filename, String userid, boolean forEncryption) throws IOException, PGPException, NoSuchProviderException { + return findPublicKey(context, filename, null, userid, forEncryption); + } - InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(context.getClassResolver(), filename); + public static PGPPublicKey findPublicKey(CamelContext context, String filename, byte[] keyRing, String userid, boolean forEncryption) + throws IOException, PGPException, NoSuchProviderException { + + InputStream is = determineKeyRingInputStream(context, filename, keyRing, forEncryption); PGPPublicKey pubKey; try { pubKey = findPublicKey(is, userid, forEncryption); @@ -62,6 +70,27 @@ public final class PGPDataFormatUtil { return pubKey; } + private static InputStream determineKeyRingInputStream(CamelContext context, String filename, byte[] keyRing, boolean forEncryption) + throws IOException { + if (filename != null && keyRing != null) { + String encryptionOrSignature; + if (forEncryption) { + encryptionOrSignature = "encryption"; + } else { + encryptionOrSignature = "signature"; + } + throw new IllegalStateException(String.format("Either specify %s file name or key ring byte array. You can not specify both.", + encryptionOrSignature)); + } + InputStream is; + if (keyRing != null) { + is = new ByteArrayInputStream(keyRing); + } else { + is = ResourceHelper.resolveMandatoryResourceAsInputStream(context.getClassResolver(), filename); + } + return is; + } + @SuppressWarnings("unchecked") private static PGPPublicKey findPublicKey(InputStream input, String userid, boolean forEncryption) throws IOException, PGPException, NoSuchProviderException { @@ -98,9 +127,13 @@ public final class PGPDataFormatUtil { public static PGPPrivateKey findPrivateKey(CamelContext context, String keychainFilename, InputStream encryptedInput, String passphrase) throws IOException, PGPException, NoSuchProviderException { + return findPrivateKey(context, keychainFilename, null, encryptedInput, passphrase); + } - InputStream keyChainInputStream = ResourceHelper.resolveMandatoryResourceAsInputStream(context.getClassResolver(), keychainFilename); + public static PGPPrivateKey findPrivateKey(CamelContext context, String keychainFilename, byte[] secKeyRing, + InputStream encryptedInput, String passphrase) throws IOException, PGPException, NoSuchProviderException { + InputStream keyChainInputStream = determineKeyRingInputStream(context, keychainFilename, secKeyRing, true); PGPPrivateKey privKey = null; try { privKey = findPrivateKey(keyChainInputStream, encryptedInput, passphrase); @@ -135,9 +168,13 @@ public final class PGPDataFormatUtil { public static PGPSecretKey findSecretKey(CamelContext context, String keychainFilename, String passphrase) throws IOException, PGPException, NoSuchProviderException { + return findSecretKey(context, keychainFilename, null, passphrase); + } - InputStream keyChainInputStream = ResourceHelper.resolveMandatoryResourceAsInputStream(context.getClassResolver(), keychainFilename); + public static PGPSecretKey findSecretKey(CamelContext context, String keychainFilename, byte[] secKeyRing, String passphrase) + throws IOException, PGPException, NoSuchProviderException { + InputStream keyChainInputStream = determineKeyRingInputStream(context, keychainFilename, secKeyRing, false); PGPSecretKey secKey = null; try { secKey = findSecretKey(keyChainInputStream, passphrase); http://git-wip-us.apache.org/repos/asf/camel/blob/e4a81eac/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 b923c2d..8597d12 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 @@ -16,17 +16,26 @@ */ package org.apache.camel.converter.crypto; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.util.IOHelper; import org.junit.Test; public class PGPDataFormatTest extends AbstractPGPDataFormatTest { + private static final String SEC_KEY_RING_FILE_NAME = "org/apache/camel/component/crypto/secring.gpg"; + private static final String PUB_KEY_RING_FILE_NAME = "org/apache/camel/component/crypto/pubring.gpg"; + + protected String getKeyFileName() { - return "org/apache/camel/component/crypto/pubring.gpg"; + return PUB_KEY_RING_FILE_NAME; } protected String getKeyFileNameSec() { - return "org/apache/camel/component/crypto/secring.gpg"; + return SEC_KEY_RING_FILE_NAME; } protected String getKeyUserId() { @@ -56,6 +65,16 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest { public void testEncryptionSigned() throws Exception { doRoundTripEncryptionTests("direct:inline-sign"); } + + @Test + public void testEncryptionKeyRingByteArray() throws Exception { + doRoundTripEncryptionTests("direct:key-ring-byte-array"); + } + + @Test + public void testEncryptionSignedKeyRingByteArray() throws Exception { + doRoundTripEncryptionTests("direct:sign-key-ring-byte-array"); + } protected RouteBuilder createRouteBuilder() { return new RouteBuilder() { @@ -121,8 +140,62 @@ public class PGPDataFormatTest extends AbstractPGPDataFormatTest { .unmarshal(pgpVerifyAndDecrypt) .to("mock:unencrypted"); // END SNIPPET: pgp-format-signature + /* ---- key ring as byte array -- */ + // START SNIPPET: pgp-format-key-ring-byte-array + PGPDataFormat pgpEncryptByteArray = new PGPDataFormat(); + pgpEncryptByteArray.setEncryptionKeyRing(getPublicKeyRing()); + pgpEncryptByteArray.setKeyUserid(keyUserid); + + PGPDataFormat pgpDecryptByteArray = new PGPDataFormat(); + pgpDecryptByteArray.setEncryptionKeyRing(getSecKeyRing()); + pgpDecryptByteArray.setKeyUserid(keyUserid); + pgpDecryptByteArray.setPassword(keyPassword); + + from("direct:key-ring-byte-array").marshal(pgpEncryptByteArray).to("mock:encrypted").unmarshal(pgpDecryptByteArray) + .to("mock:unencrypted"); + // END SNIPPET: pgp-format-key-ring-byte-array + + // START SNIPPET: pgp-format-signature-key-ring-byte-array + PGPDataFormat pgpSignAndEncryptByteArray = new PGPDataFormat(); + pgpSignAndEncryptByteArray.setKeyUserid(keyUserid); + pgpSignAndEncryptByteArray.setSignatureKeyRing(getSecKeyRing()); + pgpSignAndEncryptByteArray.setSignatureKeyUserid(keyUserid); + pgpSignAndEncryptByteArray.setSignaturePassword(keyPassword); + + PGPDataFormat pgpVerifyAndDecryptByteArray = new PGPDataFormat(); + pgpVerifyAndDecryptByteArray.setKeyUserid(keyUserid); + pgpVerifyAndDecryptByteArray.setPassword(keyPassword); + pgpVerifyAndDecryptByteArray.setEncryptionKeyRing(getSecKeyRing()); + pgpVerifyAndDecryptByteArray.setSignatureKeyUserid(keyUserid); + + from("direct:sign-key-ring-byte-array") + // encryption key ring can also be set as header + .setHeader(PGPDataFormat.ENCRYPTION_KEY_RING).constant(getPublicKeyRing()).marshal(pgpSignAndEncryptByteArray) + // it is recommended to remove the header immediately when it is no longer needed + .removeHeader(PGPDataFormat.ENCRYPTION_KEY_RING).to("mock:encrypted") + // signature key ring can also be set as header + .setHeader(PGPDataFormat.SIGNATURE_KEY_RING).constant(getPublicKeyRing()).unmarshal(pgpVerifyAndDecryptByteArray) + // it is recommended to remove the header immediately when it is no longer needed + .removeHeader(PGPDataFormat.SIGNATURE_KEY_RING).to("mock:unencrypted"); + // END SNIPPET: pgp-format-signature-key-ring-byte-array } }; } + public static byte[] getPublicKeyRing() throws Exception { + return getKeyRing(PUB_KEY_RING_FILE_NAME); + } + + public static byte[] getSecKeyRing() throws Exception { + return getKeyRing(SEC_KEY_RING_FILE_NAME); + } + + private static byte[] getKeyRing(String fileName) throws IOException { + InputStream is = PGPDataFormatTest.class.getClassLoader().getResourceAsStream(fileName); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + IOHelper.copyAndCloseInput(is, output); + output.close(); + return output.toByteArray(); + } + } http://git-wip-us.apache.org/repos/asf/camel/blob/e4a81eac/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/SpringPGPDataFormatTest.java ---------------------------------------------------------------------- diff --git a/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/SpringPGPDataFormatTest.java b/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/SpringPGPDataFormatTest.java index a31e919..1c8d6fa 100644 --- a/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/SpringPGPDataFormatTest.java +++ b/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/SpringPGPDataFormatTest.java @@ -30,5 +30,10 @@ public class SpringPGPDataFormatTest extends AbstractPGPDataFormatTest { public void testEncryption() throws Exception { doRoundTripEncryptionTests("direct:inline"); } + + @Test + public void testEncryptionWithKeyRingByteArray() throws Exception { + doRoundTripEncryptionTests("direct:pgp-key-ring-byte-array"); + } } http://git-wip-us.apache.org/repos/asf/camel/blob/e4a81eac/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 4811310..e511126 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 @@ -39,7 +39,36 @@ <to uri="mock:unencrypted"/> </route> <!-- END SNIPPET: pgp-xml-basic --> + + <!-- START SNIPPET: pgp-xml-data-format-bean-with-keyring-bytearray --> + <route> + <from uri="direct:pgp-key-ring-byte-array"/> + <marshal ref="encryptBean"/> + <to uri="mock:encrypted"/> + <unmarshal ref="decryptBean"/> + <to uri="mock:unencrypted"/> + </route> </camelContext> - + <bean id="encryptBean" class="org.apache.camel.converter.crypto.PGPDataFormat"> + <property name="keyUserid" value="[email protected]"/> + <property name="encryptionKeyRing" ref="pubKeyRing"/> + </bean> + + <bean id="decryptBean" class="org.apache.camel.converter.crypto.PGPDataFormat"> + <property name="keyUserid" value="[email protected]"/> + <property name="encryptionKeyRing" ref="secKeyRing"/> + <property name="password" value="sdude"/> + </bean> + + <!-- bean represents the publik 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 id="secKeyRing" + class="org.apache.camel.converter.crypto.PGPDataFormatTest" + factory-method="getSecKeyRing" /> + <!-- END SNIPPET: pgp-xml-data-format-bean-with-keyring-bytearray --> </beans> \ No newline at end of file
