RC
Uncategorized

PGP Encryption of DATA in Mule ESB

Security is the main concern of all IT implementation in today’s world. Especially when you are sending your important confidential data over the network, Since Mule ESB is a integration platform in which we plug many different kind of systems…

Harish Kumar
Share

Security is the main concern of all IT implementation in today’s world. Especially when you are sending your important confidential data over the network, Since Mule ESB is a integration platform in which we plug many different kind of systems and share data between them it’s no wonder security is one of main concern for Mule ESB also.

Today I will be writing about how to use Pretty Good Privacy (PGP) to encrypt and decrypt your data or file when you use mule ESB to transfer them to different systems.

How PGP works

Pretty Good Privacy uses a variation of the public key system. In this system, each user has an encryption key that is publicly known and a private key that is known only to that user. You encrypt a message you send to someone else using their public key. When they receive it, they decrypt it using their private key. Since encrypting an entire message can be time-consuming, PGP uses a faster encryption algorithm to encrypt the message and then uses the public key to encrypt the shorter key that was used to encrypt the entire message. Both the encrypted message and the short key are sent to the receiver who first uses the receiver’s private key to decrypt the short key and then uses that key to decrypt the message.

More details about PGP at http://www.pgpi.org/doc/pgpintro/

Let’s get started with the implementation of PGP on our message payload. So the idea is we will be having two pgp keys let’s say for Company 1 and Company 2 these two companies want to share data between themselves.

screen-shot-2016-09-21-at-12-02-07-am

 

So, Company 1 will encrypt the sending data by using the Public PGP key of Company 2 and once Company 2 receives this data they will decrypt this data by using the private key of Company 2 since the data is encrypted with their own public key only they can decrypt it using their own private key.

screen-shot-2016-09-21-at-12-02-16-am

 

Same process will happen when Company 2 wants to send data to Company 1 but this time the encryption happens with Public key of company 1 and decryption on Company 1 side happens with the private key of Company 1.

In PGP once we have these keys available to us using Open PGP commands on Linux or windows we can import the keys of other parties to our key ring file i.e. named as pubring.gpg and our own private key will be available in secring.gpg, these two files play a major role in encryption and decryption in mule, so what we need to do is copy these two files to resources folder of mule esb project

screen-shot-2016-09-21-at-12-02-24-am

 

The details about the principal of keys, and the file location of pubring.gpg and secring.gpg we will be configuring in runtime environment properties so that we can make them dynamic and do changes for different servers such as during testing we will be able to use test keys and for production servers we will configure to use production keys.

Now, we will be writing two Java classes to get access to the keys from the pubring and secring files, let’s first see the java class then I will give more details about their use.

  1. java this class implements org.mule.api.security.CredentialsAccessor and it will be giving as a access to the different keys based on the principal values that we provide it using spring configuration.
package com.pgpdemo.security;

import java.io.InputStream;

import java.util.HashMap;

import java.util.Iterator;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import org.bouncycastle.openpgp.PGPPublicKey;

import org.bouncycastle.openpgp.PGPPublicKeyRing;

import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;

import org.bouncycastle.openpgp.PGPSecretKey;

import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;

import org.mule.api.lifecycle.Initialisable;

import org.mule.api.lifecycle.InitialisationException;

import org.mule.config.i18n.CoreMessages;

import org.mule.module.pgp.PGPKeyRing;

import org.mule.util.IOUtils;

public class PGPKeyRingImpl implements PGPKeyRing, Initialisable {

    protected static final Log logger = LogFactory.getLog(PGPKeyRingImpl.class);

    private String publicKeyRingFileName;

    private HashMap<String, PGPPublicKey> principalsKeyBundleMap;

    private String secretKeyRingFileName;

    private String secretAliasId;

    private PGPSecretKey secretKey;

    private String secretPassphrase;

    public void initialise() throws InitialisationException {

        try {

            java.security.Security.addProvider(new BouncyCastleProvider());

            principalsKeyBundleMap = new HashMap<String, PGPPublicKey>();

            readPublicKeyRing();

            readPrivateKeyBundle();

        } catch (Exception e) {

            logger.error("Error in initialise:" + e.getMessage(), e);

            throw new InitialisationException(CoreMessages.failedToCreate("PGPKeyRingImpl"), e, this);

        }

    }

    private void readPublicKeyRing() throws Exception {

        InputStream in = IOUtils.getResourceAsStream(getPublicKeyRingFileName(), getClass());

        PGPPublicKeyRingCollection collection = new PGPPublicKeyRingCollection(in);

        in.close();

        for (Iterator iterator = collection.getKeyRings(); iterator.hasNext();) {

            PGPPublicKeyRing ring = (PGPPublicKeyRing) iterator.next();

            String userID = "";

            for (Iterator iterator2 = ring.getPublicKeys(); iterator2.hasNext();) {

                PGPPublicKey publicKey = (PGPPublicKey) iterator2.next();

                Iterator userIDs = publicKey.getUserIDs();

                if (userIDs.hasNext()) {

                    userID = (String) userIDs.next();

                }

                principalsKeyBundleMap.put(userID, publicKey);

            }

        }

    }

    private void readPrivateKeyBundle() throws Exception {

        InputStream in = IOUtils.getResourceAsStream(getSecretKeyRingFileName(), getClass());

        PGPSecretKeyRingCollection collection = new PGPSecretKeyRingCollection(in);

        in.close();

        secretKey = collection.getSecretKey(Long.valueOf(getSecretAliasId()));

    }

    public String getSecretKeyRingFileName() {

        return secretKeyRingFileName;

    }

    public void setSecretKeyRingFileName(String value) {

        this.secretKeyRingFileName = value;

    }

    public String getSecretAliasId() {

        return secretAliasId;

    }

    public void setSecretAliasId(String value) {

        this.secretAliasId = value;

    }

    public String getSecretPassphrase() {

        return new String(secretPassphrase);

    }

    public void setSecretPassphrase(String value) {

        this.secretPassphrase = value;

    }

    public PGPSecretKey getSecretKey() {

        return secretKey;

    }

    public String getPublicKeyRingFileName() {

        return publicKeyRingFileName;

    }

    public void setPublicKeyRingFileName(String value) {

        this.publicKeyRingFileName = value;

    }

    public PGPPublicKey getPublicKey(String principalId) {

        return principalsKeyBundleMap.get(principalId);

    }

}
<spring:bean id="pgpKeyManager" class="com.pgpdemo.security.PGPKeyRingImpl" init-method="initialise">
    <spring:property name="publicKeyRingFileName" value="${pgp.encryption.public.keyring.filename}" />
    <spring:property name="secretKeyRingFileName" value="${pgp.encryption.secret.keyring.fileName}" />
    <spring:property name="secretAliasId" value="${pgp.encryption.secret.aliasid}" />
    <spring:property name="secretPassphrase" value="${pgp.encryption.secret.passphrase}" />
</spring:bean>

 

  1. java implements org.mule.api.lifecycle.Initialisable and org.bouncycastle.openpgp.PGPPublicKey this is the object where mule will keep all the public and private keys based on the files that we provide i.e. pubring.gpg and secring.gpg

 

package com.pgpdemo.security;
import java.util.Map;
import org.apache.log4j.Logger;
import org.mule.api.MuleEvent;
import org.mule.api.security.CredentialsAccessor;
import org.mule.api.transport.PropertyScope;
public class PGPCredentialAccessor implements CredentialsAccessor {
    private Map<String, String> pgpKeysMap;
    Logger logger = Logger.getLogger(PGPCredentialAccessor.class);
    public PGPCredentialAccessor() {
    }
    public Object getCredentials(MuleEvent event) {
        logger.debug("getCredentials(MuleEvent event)");
        String credentials = null;
        @SuppressWarnings("deprecation")
        String keyName = (String) event.getMessage().getProperty("PGP_KEY", PropertyScope.ALL_SCOPES);
        credentials = getPGPKeysMap().get(keyName);
        return credentials;
    }
    public void setCredentials(MuleEvent event, Object credentials) {
        logger.debug("setCredentials(MuleEvent event, Object credentials)");
    }
    public Map<String, String> getPGPKeysMap() {
        return pgpKeysMap;
    }
    public void setAxaPGPKeysMap(Map<String, String> axaPGPKeysMap) {
        this.pgpKeysMap = axaPGPKeysMap;
    }
}
<spring:bean id="credentialsAccessor" class="com.pgpdemo.security.PGPCredentialAccessor">
    <spring:property name="axaPGPKeysMap">
        <spring:map>
        <spring:entry key="Company_1_Key" value="${pgp.company_1.encryption.principal}"/>
        <spring:entry key="Company_2_Key" value="${pgp.company_2.encryption.principal}"/>
        </spring:map>
    </spring:property>
</spring:bean>

 

  1. We will be creating a Security Manager that will use above two class to implement PGP security in Mule ESB
<pgp:security-manager>
    <pgp:security-provider name="pgpSecurityProvider"     keyManager-ref="pgpKeyManager" />
    <pgp:keybased-encryption-strategy     name="keyBasedEncryptionStrategy" keyManager-ref="pgpKeyManager"     credentialsAccessor-ref="credentialsAccessor" />
</pgp:security-manager>
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml"     xmlns:pgp="http://www.mulesoft.org/schema/mule/pgp" xmlns:context="http://www.springframework.org/schema/context"     xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:encryption="http://www.mulesoft.org/schema/mule/encryption"     xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"     xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-current.xsd     http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd     http://www.mulesoft.org/schema/mule/encryption http://www.mulesoft.org/schema/mule/encryption/current/mule-encryption.xsd     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd     http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd     http://www.mulesoft.org/schema/mule/pgp http://www.mulesoft.org/schema/mule/pgp/3.7/mule-pgp.xsd">
<spring:beans>
    <spring:bean id="pgpKeyManager" class="com.pgpdemo.security.PGPKeyRingImpl"     init-method="initialise">
    <spring:property name="publicKeyRingFileName" value="${pgp.encryption.public.keyring.filename}" />
    <spring:property name="secretKeyRingFileName" value="${pgp.encryption.secret.keyring.fileName}" />
    <spring:property name="secretAliasId" value="${pgp.encryption.secret.aliasid}" />
    <spring:property name="secretPassphrase" value="${pgp.encryption.secret.passphrase}" />
</spring:bean>
<spring:bean id="credentialsAccessor"     class="com.pgpdemo.security.PGPCredentialAccessor">
        <spring:property name="axaPGPKeysMap">
            <spring:map>
                <spring:entry key="Company_1_Key" value="${pgp.company_1.encryption.principal}"/>
                <spring:entry key="Company_2_Key" value="${pgp.company_2.encryption.principal}"/>
            </spring:map>
        </spring:property>
    </spring:bean>
</spring:beans>
<pgp:security-manager>
    <pgp:security-provider name="pgpSecurityProvider"     keyManager-ref="pgpKeyManager" />
    <pgp:keybased-encryption-strategy     name="keyBasedEncryptionStrategy" keyManager-ref="pgpKeyManager"     credentialsAccessor-ref="credentialsAccessor" />
</pgp:security-manager>
</mule>

So now we are ready with the hard part of PGP security implementation in mule ESB, now we just have to use in our flows, I will be creating two flows for encryption and decryption.

  1. Encryption flow – in this flow we will be sending a plain text data and the flow will respond with the encrypted data to us.
  2. Decryption flow – in this we will be using the encrypted data from flow 1 and try to decrypt it and get the plain text data back, In real world we should not be able to decrypt the data because we will not be having the private key of Company 2 since we encrypt with Public key of Company 2 but just for demo purpose I am going to encrypt with Same companies public key and then try to decrypt it.

screen-shot-2016-09-21-at-12-02-46-am

Here are the results for the two tests

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:encryption="http://www.mulesoft.org/schema/mule/encryption"     xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core"     xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"     xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd     http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd     http://www.mulesoft.org/schema/mule/encryption http://www.mulesoft.org/schema/mule/encryption/current/mule-encryption.xsd">
    <http:listener-config name="HTTP_Listener_Configuration"         host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration" />
    <flow name="enctestFlow">
        <http:listener config-ref="HTTP_Listener_Configuration"         path="/enctest" doc:name="HTTP_enc" allowedMethods="POST" />
        <logger message="#[payload]" level="INFO" doc:name="Logger" />
        <set-property propertyName="PGP_KEY" value="Company_1_Key"             doc:name="PGP KEY Property" />
        <encrypt-transformer name="pgpEncryptTest"             strategy-ref="keyBasedEncryptionStrategy" />
        <logger message="#[payload]" level="INFO" doc:name="Logger" />
    </flow>
<flow name="dectestFlow">
    <http:listener config-ref="HTTP_Listener_Configuration"         path="/dectest" allowedMethods="POST" doc:name="HTTP" />
    <object-to-string-transformer doc:name="Object to String" encoding="UTF-8" />
    <logger message="#[payload]" level="INFO" doc:name="Logger" />
    <set-property propertyName="PGP_KEY" value="Company_1_Key"         doc:name="PGP KEY Property" />
    <decrypt-transformer name="pgpDecryptTest"         strategy-ref="keyBasedEncryptionStrategy" />
    <logger message="#[payload]" level="INFO" doc:name="Logger" />
    </flow>
</mule>

Encryption

 

screen-shot-2016-09-21-at-12-02-54-am

Using the same encrypted text, now the Decryption

 

screen-shot-2016-09-21-at-12-03-01-am

So there we have implimented PGP encrypt/decrypt on our payload, now you can safely transfer data between two entities without worring about someone reading your data.

You will notice that I have not used Mule ESB provided default PGP implimentation, the reason for that is I wanted more control over my PGP keys and if required I wanted to be able to impliment custom logic on my PGP keys.

Refrences:

http://www.pgpi.org/doc/pgpintro/

https://docs.mulesoft.com/mule-user-guide/v/3.6/pgp-encrypter

 

Related reading