Skip to Content

PGP Encryption/Decryption using java code

I came across a business requirement where I need to encrypt the data (which were coming from SAP ECC) and sent to a FTP. This was a Proxy to File Scenario. The main challenge was how to encrypt the data.

 

PGP Encryption/Decryption can be done in mapping time (in case of java mapping). These below steps show how to do encryption/decryption in java mapping. In this case no need to get Licensing from any company. (No adapter module etc).

 

 

Step 1:

Download two jar files from http://www.bouncycastle.org/latest_releases.html

  1. bcprov-ext-jdk14-145.jar
  2. bcpg-jdk14-145.jar

These two jars are open source and you can download from the java code also from www.bouncycastle.org.

 

Step2:

 

            If you import these two jars in Integration Repository->Imported archive, your mapping will not work.

You need to deploy these two jars at your JVM. j2re1.4.2_17\lib\ext. I am using JRE 1.4.

If your java code is not able to find these jars(Bouncy Castle), restart PI server.

 

For unit test in your NWDS (eclipse) you can add these jars. Right Click on Project–Properties->Java Build Path->Add External Jars.

 

Step3:  Generate Public and Private Key Rings.

            PGP public (for encryption) and private key (for decryption) should be provided by your basis person. For testing purpose you can create this pair. To create public/private key pair, download PGP freeware software and install at your desktop.

 

http://www.pgpi.org/products/pgp/versions/freeware/winxp/8.0/

 

You can find other versions of this software for different platforms.

After installation, it will provide you the guideline to create the public key and private key.

Below are images showing how to create the same.

Click on New Key and on next page click on “Next” button.

You can put any name and email id.

In next screen, choose Diffie-Hellman/DSS and 2048 bits strength (you can choose the lower and higher strength also).

When keys are created you can find those at Edit->Options->Files (tab). It will show the path to public and private key rings.

 

These keys rings need to be archived. Make jar and upload them into Integration Repository->Imported archive.

 

For unit testing in NWDS (eclipse) you can copy these key rings in your package.

 

Step 4:

            Develop java mapping program (I am using PI 7.0) and call the encrypt/decrypt method to do Encryption/Decryption.

 

Java Mapping for Encryption

 

package com.sap.pi.pgp;

 

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Map;

import com.sap.aii.mapping.api.AbstractTrace;

import com.sap.aii.mapping.api.StreamTransformation;

import com.sap.aii.mapping.api.StreamTransformationConstants;

import com.sap.aii.mapping.api.StreamTransformationException;

 

public class PGPEncryption implements StreamTransformation {

      private Map param;

      private AbstractTrace trace;

 

      public void setParameter(Map param) {

            this.param = param;

      }

 

      public void execute(InputStream in, OutputStream out) throws StreamTransformationException {

            if (param instanceof java.util.Map) {

                  trace = (AbstractTrace) ((Map) param).get(StreamTransformationConstants.MAPPING_TRACE);

            }

            try {

                  String publicKeyPath = “/com/sap/pi/pgp/publickey.pkr”;

                  // Encrypt the message

                  new PGPCrypto().encrypt(publicKeyPath, in, out, trace);

            } catch (Exception e) {

                  e.printStackTrace();

            }

      }

 

      // for unit testing.

      public static void main(String[] args) throws Exception {

            try {

                  new PGPEncryption().execute(new FileInputStream(“C:\\PGP\\plainText.txt”), new FileOutputStream(

                              “C:\\PGP\\CypherText.asc”));

            } catch (Exception e) {

            }

      }

}

 

 

 

Java Mapping for Decryption:

While decryption, you need to provide the passphrase which you entered while creating public-private key pair. It will call decrypt method which is in PGPCrypto class.

 

 

package com.sap.pi.pgp;

 

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.Map;

 

import com.sap.aii.mapping.api.AbstractTrace;

import com.sap.aii.mapping.api.StreamTransformation;

import com.sap.aii.mapping.api.StreamTransformationConstants;

import com.sap.aii.mapping.api.StreamTransformationException;

 

public class PGPDecryption implements StreamTransformation {

      private Map param;

      private AbstractTrace trace;

 

      public void setParameter(Map param) {

            this.param = param;

      }

 

      public void execute(InputStream in, OutputStream out) throws StreamTransformationException {

            if (param instanceof java.util.Map) {

                  trace = (AbstractTrace) ((Map) param).get(StreamTransformationConstants.MAPPING_TRACE);

            }

            try {

                  new PGPCrypto().decrypt(in, out, “/com/sap/pi/pgp/Secring_dev.skr”, “Passphrase”, trace);

            } catch (Exception e) {

                  e.printStackTrace();

            }

      }

 

      // for unit testing.

      public static void main(String[] args) throws Exception {

            try {

                  new PGPDecryption().execute(new FileInputStream(“C:\\PGP\\CypherText.asc”), new FileOutputStream(“C:\\PGP\\plainText_N.txt”));

            } catch (Exception e) {

            }

      }

}

 

 

 

In above two examples (encryption and decryption) public key ring and private key ring are imported in Integration Repository->Imported Archive.

 If you are using eclipse, it package view should look like below.

Encrypt and decrypt methods are in PGPCrypto class.

 

Java Code of class PGPCrypto is below. You can compile this class at JRE1.4 or any compatible version and make JAR file and import in Integration Repository->Imported Archive. 

 

 

package com.sap.pi.pgp;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.UnsupportedEncodingException;

import java.security.NoSuchProviderException;

import java.security.SecureRandom;

import java.security.Security;

import java.util.Date;

import java.util.Iterator;

 

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.PGPOnePassSignatureList;

import org.bouncycastle.openpgp.PGPPrivateKey;

import org.bouncycastle.openpgp.PGPPublicKey;

import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;

import org.bouncycastle.openpgp.PGPPublicKeyRing;

import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;

import org.bouncycastle.openpgp.PGPSecretKey;

import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;

import org.bouncycastle.openpgp.PGPUtil;

 

import com.sap.aii.mapping.api.AbstractTrace;

 

public class PGPCrypto {

      private AbstractTrace trace;

 

      public void encrypt(InputStream in, OutputStream out) throws Exception {

            String publicKeyPath = “/com/pi/edt/pgp/resources/keys/pubring_dev.pkr”;

            try {

                  encrypt(publicKeyPath, inputStreamToString(in), out, trace);

            } catch (Exception e) {

                  e.printStackTrace();

                  throw new Exception(e.toString());

            }

      }

 

      public void encrypt(String publicKeyPath, InputStream in, OutputStream out, AbstractTrace trace) throws Exception {

            try {

                  encrypt(publicKeyPath, inputStreamToString(in), out, trace);

            } catch (Exception e) {

                  e.printStackTrace();

                  throw new Exception(e.toString());

           }

      }

 

      public void encrypt(String publicKeyPath, String inString, OutputStream out, AbstractTrace trace) throws Exception {

            this.trace = trace;

            try {

                  Security.addProvider(new BouncyCastleProvider());

                  InputStream keyStream = getClass().getResourceAsStream(publicKeyPath);

                  if (keyStream == null) {

                        throw new Exception(“Unable to find Resource at ” + publicKeyPath, new Exception(“Resource \”” + publicKeyPath

                                    + “\” not available. Please check the path or file name.”));

                  }

                  // Get Publik key

                  PGPPublicKey key = readPublicKeyFromCol(keyStream);

                  out = new DataOutputStream(out);

                  ByteArrayOutputStream bOut = new ByteArrayOutputStream();

                  PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZIP);

                  writeStringToLiteralData(comData.open(bOut), inString);

                  comData.close();

                  // object that encrypts the data

                  if (trace != null) {

                        trace.addInfo(“Trace1: Going to encrypt the data”);

                  }

                  PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5, new SecureRandom(),

                              “BC”);

                  cPk.addMethod(key);

 

                  byte[] bytes = bOut.toByteArray();

                  out = cPk.open(out, bytes.length);

                  out.write(bytes);

                  cPk.close();

                  out.close();

            } catch (Exception e) {

                  e.printStackTrace();

                  throw new Exception(e.toString());

            }

      }

 

      private String inputStreamToString(InputStream in) {

            // read in stream into string.

            StringBuffer buf = new StringBuffer();

            try {

                  InputStreamReader isr = null;

                  // try UTF-8 conversion

                  try {

                        isr = new InputStreamReader(in, “UTF-8”);

                  } catch (UnsupportedEncodingException e) {

                        // or atleast in natural encoding

                        isr = new InputStreamReader(in);

                  }

                  int c = 0;

                  while ((c = isr.read()) != -1) {

                        buf.append((char) c);

                  }

                  in.close();

                  isr.close();

            } catch (IOException e) {

                  e.printStackTrace();

            }

            return buf.toString();

      }

 

      private void writeStringToLiteralData(OutputStream out, String inString) throws IOException {

            PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();

            OutputStream pOut = lData.open(out, PGPLiteralData.BINARY, “”, inString.length(), new Date());

            pOut.write(inString.getBytes());

            lData.close();

      }

 

      private PGPPublicKey readPublicKeyFromCol(InputStream in) throws Exception {

            PGPPublicKeyRing pkRing = null;

            PGPPublicKey result = null, key = null;

            try {

                  PGPPublicKeyRingCollection pkCol = new PGPPublicKeyRingCollection(in);

                  Iterator it = pkCol.getKeyRings();

                  while (it.hasNext()) {

                        pkRing = (PGPPublicKeyRing) it.next();

                        Iterator pkIt = pkRing.getPublicKeys();

                        while (pkIt.hasNext()) {

                              key = (PGPPublicKey) pkIt.next();

                              if (key.isEncryptionKey()) {

                                    result = key;

                                    break;

                              }

                        }

                  }

            } catch (Exception e) {

                  e.printStackTrace();

                  throw new Exception(e.toString());

            }

            return result;

      }

 

      public void decrypt(InputStream in, OutputStream out, String passphrase, AbstractTrace trace) throws Exception {

            String privateKeyPath = “/com/pi/edt/pgp/resources/keys/Secring_dev.skr”;

            try {

                  InputStream inKey = null;

                  try {

                        inKey = getClass().getResourceAsStream(privateKeyPath);

                  } catch (Exception e) {

                        e.printStackTrace();

                        throw new Exception(e.toString());

                  }

                  decrypt(in, out, inKey, passphrase.toCharArray(), trace);

            } catch (Exception e) {

                  e.printStackTrace();

                  throw new Exception(e.toString());

            }

      }

 

      public void decrypt(InputStream encData, OutputStream out, String privateKeyPath, String passphrase, AbstractTrace trace)

                  throws Exception {

            try {

                  InputStream inKey = null;

                  try {

                        inKey = new Object().getClass().getResourceAsStream(privateKeyPath);

                  } catch (Exception e) {

                        e.printStackTrace();

                        thrownew Exception(e.toString());

                  }

                  decrypt(encData, out, inKey, passphrase.toCharArray(), trace);

            } catch (Exception e) {

                  e.printStackTrace();

                  throw new Exception(e.toString());

            }

      }

 

      public void decrypt(String encData, OutputStream out, String privateKeyPath, String passphrase, AbstractTrace trace)

                  throws Exception {

            try {

                  InputStream in = null;

                  InputStream inKey = null;

                  try {

                        in = new ByteArrayInputStream(encData.getBytes(“UTF-8”));

                  } catch (UnsupportedEncodingException e) {

                        in = new ByteArrayInputStream(encData.getBytes());

                  }

                  try {

                        inKey = getClass().getResourceAsStream(privateKeyPath);

                  } catch (Exception e) {

                        e.printStackTrace();

                        throw new Exception(e.toString());

                  }

                  decrypt(in, out, inKey, passphrase.toCharArray(), trace);

            } catch (Exception e) {

                  e.printStackTrace();

                  throw new Exception(e.toString());

            }

      }

 

      public void decrypt(InputStream encdata, OutputStream out, InputStream key, char passphrase[], AbstractTrace trace)

                  throws Exception {

            Security.addProvider(new BouncyCastleProvider());

            try {

                  encdata = PGPUtil.getDecoderStream(encdata);

                  PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(encdata);

                  PGPEncryptedDataList enc;

                  Object o = pgpObjectFactory.nextObject();

 

                  if (o instanceof PGPEncryptedDataList) {

                        enc = (PGPEncryptedDataList) o;

                  } else {

                        enc = (PGPEncryptedDataList) pgpObjectFactory.nextObject();

                  }

 

                  Iterator it = enc.getEncryptedDataObjects();

                  PGPPrivateKey sKey = null;

                  PGPPublicKeyEncryptedData pbe = null;

                  while (sKey == null && it.hasNext()) {

                        pbe = (PGPPublicKeyEncryptedData) it.next();

                        sKey = findSecretKey(key, pbe.getKeyID(), passphrase);

                  }

                  if (sKey == null) {

                        throw new IllegalArgumentException(“secret key for message not found.”);

                  }

                  InputStream clear = pbe.getDataStream(sKey, “BC”);

                  PGPObjectFactory plainFact = new PGPObjectFactory(clear);

                  Object message = plainFact.nextObject();

                  if (message instanceof PGPCompressedData) {

                        PGPCompressedData cData = (PGPCompressedData) message;

                        PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream());

                        message = pgpFact.nextObject();

                  }

                  ByteArrayOutputStream baos = new ByteArrayOutputStream();

                  if (message instanceof PGPLiteralData) {

                        PGPLiteralData ld = (PGPLiteralData) message;

                        InputStream unc = ld.getInputStream();

                        int ch;

                        while ((ch = unc.read()) >= 0) {

                              baos.write(ch);

                        }

                  } else if (message instanceof PGPOnePassSignatureList) {

                        throw new PGPException(“encrypted message contains a signed message – not literal data.”);

                  } else {

                        throw new PGPException(“message is not a simple encrypted file – type unknown.”);

                  }

 

                  // write outputstream

                  out.write(baos.toString().getBytes());

            } catch (Exception e) {

                  e.printStackTrace();

                  throw new Exception(e.toString());

            }

      }

 

      private static PGPPrivateKey findSecretKey(InputStream keyIn, long keyID, char[] pass) throws IOException, PGPException,

                  NoSuchProviderException {

            PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));

            PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);

            if (pgpSecKey == null) {

                  return null;

            }

            return pgpSecKey.extractPrivateKey(pass, “BC”);

      }

}

 

If you want to do PGP encryption/decryption at adapter level, you need to create adapter module and import public/private keys in Visual admin and read the same from there using java code.

10 Comments
You must be Logged on to comment or reply to a post.
  • Hi Sandeep, Great Blog, I have waiting this kind of information.

    Do we need to update java.security to register Bouncy Castle and download US_export_policy.jar and local_policy.jar ?

    Please advise ?

    Best Regards

    Fernand

    • Thanks Fernand.
      No need to edit java.security file because in above java code BouncyCastleProvider is added dynamically.

      Security.addProvider(new BouncyCastleProvider());

      If you are adding security provider in java.security file, remove the above line from java code. It will work.

      Yes, you need to download US_export_policy.jar and local_policy.jar and put in lib\security folder.

      Thanks,
      Sandeep Maurya

  • Hi Sandeep,
                I was trying this out. I get and exception as follows while trying to decrypt.
    I have the security policy jars in place ” lib/security”

    Can you provide the details of what key you used?
    Or how you solved this?
    N.B: I use an NWDS 7.2 for this development

    org.bouncycastle.openpgp.PGPException: Exception decrypting key
         at org.bouncycastle.openpgp.PGPSecretKey.extractKeyData(Unknown Source)
         at org.bouncycastle.openpgp.PGPSecretKey.extractPrivateKey(Unknown Source)
         at org.bouncycastle.openpgp.PGPSecretKey.extractPrivateKey(Unknown Source)
         at com.sap.pi.pgp.PGPCrypto.findSecretKey(PGPCrypto.java:538)
         at com.sap.pi.pgp.PGPCrypto.decrypt(PGPCrypto.java:453)
         at com.sap.pi.pgp.PGPCrypto.decrypt(PGPCrypto.java:353)
         at com.sap.pi.pgp.PGPDecryption.execute(PGPDecryption.java:53)
         at com.sap.pi.pgp.PGPDecryption.main(PGPDecryption.java:71)
    Caused by: java.security.InvalidKeyException: Illegal key size
         at javax.crypto.Cipher.a(DashoA13*..)
         at javax.crypto.Cipher.init(DashoA13*..)
         at javax.crypto.Cipher.init(DashoA13*..)

  • Hi,

    I’m having the following error in PI:

    com.sap.aii.ibrep.server.mapping.rt.WrappedMappingRuntimeException: Unable to find resource org/bouncycastle/jce/provider/BouncyCastleProvider.class (http://www.xxx.com.br, -1) in the following software component versions: b8040540-dfb8-11dc-b688-c07f0a600396          

    I have deployed a .sda file containing the following jars:

    bcpkix-jdk14-147;

    bcprov-ext-jdk14-147;

    bcprov-jdk14-147.

    Sandeep, can u help me?

    Thanks in advanced.