Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Ajith_Nair
Explorer

In this blog, I will retrace the steps that I have used to encrypt and decrypt payload coming inside message tags using PGP encryption/decryption. After many searches and tries, I was able to find a blog by Sandeep using Bouncy Castle,
https://community.sap.com/t5/additional-blogs-by-members/pgp-encryption-decryption-using-java-code/b...
This is an update to the same blog where I have worked around the mentioned trick without using Bouncy Castle to add the encrypted payload within the messages.

For OpenPGP encryption and decryption, the requirement that I had was to convert the generated message through BCM(Bank Communication Management) by first encrypting with PGP encryption and then converting to base64 while having this within the payload.

INBOUND flowINBOUND flow

 

  1. Download the necessary libraries required.
    bcpg-lw-jdk15on-1.70.jar
    bcprov-lw-jdk15on-1.70.jar
    pgplib-3.2.3.jar
    com.sap.xi.mapping.tool.lib_api.jar
    com.sap.xpi.ib.mapping.lib.jar

    You can get the first 3 libraries from the below link
    https://didisoft.com/java-openpgp/
    The other 2 libraries are sap standard libraries used in Java mapping or any UDF concerned, if required I will also try to attach the same on edit.

  2. Next step, you have to generate your keys, I have used GPG4WIN 3.1.9 to generate keys
    keys.jpg

    Post your keys generation, you will have 3 keys, one public key from the bank and 2 keys generated at your end, one public and one private.

  3. You have to store the keys in the OS folder such that your Java code can access the keys, I have mentioned the path in which I have stored them for your reference. You have to use SKR for private keys and PKR extension for public keys.
    /usr/sap/XXX/X00/<your_custom_folder>/privatekey.skr
  4. I have used Eclipse for my Java code development, as currently NWDS is not available. Below is the reference path of the package I have used, I have inserted keys within the package and reference libraries which I have uploaded.
    package contentpackage content
    reference librariesreference libraries

  5. Below is the encryption Java code that I have used, I have used many "getTrace" code which is for my reference, you can remove them or add additional ones based on what you prefer during testing.

 

 

package z001;

import java.io.InputStream;
import java.io.OutputStream;
import com.sap.aii.mapping.api.*;
import java.io.*;
import java.util.Base64;
import com.didisoft.pgp.PGPLib;
public class encrypt extends AbstractTransformation {
	 @Override

	    public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput) throws StreamTransformationException {
		 try{     
		       
			    PGPLib pgp = new PGPLib();
			     String privateKeyFile = "/usr/sap/XXX/X00/<your_custom_folder>/privatekey.skr";
			     String privateKeyPassword = "<your_key_password>";

			     String publicEncryptionKeyFile = "/usr/sap/XXX/X00/<your_custom_folder>/bankkey.pkr";        
			     
		        InputStream inputStream = transformationInput.getInputPayload().getInputStream();
		        
		        BufferedReader inpxml = new BufferedReader(new InputStreamReader(inputStream));
		        getTrace().addInfo("input received");
		        StringBuffer buffer = new StringBuffer();
				   String line="";
				   while ((line = inpxml.readLine()) != null)
				   {
				   buffer.append(line);
				   }
				   String org_msg=buffer.toString();
				
				   OutputStream outputstream = transformationOutput.getOutputPayload().getOutputStream();
				   
				   getTrace().addInfo("encrypt");
				   
				   String signedAndEncryptedString = 
					          pgp.signAndEncryptString(org_msg,
					                                   privateKeyFile, 
					                                   privateKeyPassword, 
					                                   publicEncryptionKeyFile);
				   
				   getTrace().addInfo("encode");
				   
				   byte[] bytes = signedAndEncryptedString.getBytes(); 
				   String encodedString = Base64.getEncoder().encodeToString(bytes);
//					   int msg_length = org_msg.length();
				   getTrace().addInfo("finalstructure");
				   String target_msg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+"<ns0:MT_bank_Pay_Request xmlns:ns0=\"http://x.com/bank_Payment\">"+"<paymentBase64>"+encodedString+"</paymentBase64>"+"</ns0:MT_bank_Pay_Request>";
				   outputstream.write(target_msg.getBytes());
//this is to get the final target message that we have converted
				   getTrace().addInfo("finalstructure"+target_msg);
		 }
		   catch (Exception ie) {
		  }
		      
	    } 
}​

 

 

This will convert the final message below

 

 

<?xml version="1.0" encoding="UTF-8">
​<ns0:MT_bank_Pay_Request xmlns:ns0="http://x.com/bank_Payment">

<paymentBase64>"your encoded and encrypted string"</paymentBase64>

</ns0:MT_bank_Pay_Request>

 

 

 

OUTBOUND flowOUTBOUND flow
This is the response from the bank side that I was receiving, here in responsebase64 I had the original file content response, which needed to be decoded and decrypted.

 

 

<?xml version="1.0" encoding="UTF-8"?>
<ns0:MT_Vendor_Pay_Response xmlns:ns0="http://x.com/bank_Payment">
   <referenceId>1</referenceId>
   <profileId>2</profileId>
   <statusCode>3</statusCode>
   <statusDesc>5</statusDesc>
   <responseBase64>6</responseBase64>
</ns0:MT_Vendor_Pay_Response>

 

 


For decryption, in the below Java code, you can see the original content (which is encrypted and encoded) is within the responsebase64 tag, if blank I am generating a different XML response, but if non-blank I will be consuming the payload within SAP PO. Integration response will be generally provided by the bank side, you can add the dummy payload as same as the response you are having from the bank.

 

 

package z001;

import com.sap.aii.mapping.api.*;
import java.io.*;
import java.util.Base64;
import com.didisoft.pgp.PGPLib;

public class decrypt extends AbstractTransformation {
	@Override
	public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput)
			throws StreamTransformationException {
		try {
			PGPLib pgp = new PGPLib();
			String privateKeyFile = "/usr/sap/XXX/X00/<your_custom_folder>/privatekey.skr";
			String privateKeyPassword = "<your_key_password>";

			InputStream inputStream = transformationInput.getInputPayload().getInputStream();
			OutputStream outputstream = transformationOutput.getOutputPayload().getOutputStream();

			BufferedReader inpxml = new BufferedReader(new InputStreamReader(inputStream));
			getTrace().addInfo("input received");
			String originalFileName = "";
			StringBuffer buffer = new StringBuffer();
			String line = "";
			while ((line = inpxml.readLine()) != null) {
				buffer.append(line);
			}
			String org_msg = buffer.toString();
			String s3 = org_msg;
			String isFound = "";
			String headerstatus = "";
			String headerdesc = "";
			String responsebase64 ;
			headerstatus = s3;
			headerdesc = s3;
			responsebase64 = s3;
//I have used index here as my response was having status code and message
//which i have capture in local variable.
			headerstatus = headerstatus.substring(headerstatus.indexOf("<statusCode>") + 12);
			headerstatus = headerstatus.substring(0, headerstatus.indexOf("</statusCode>"));
			getTrace().addInfo(headerstatus);

			headerdesc = headerdesc.substring(headerdesc.indexOf("<statusDesc>") + 12);
			headerdesc = headerdesc.substring(0, headerdesc.indexOf("</statusDesc>"));
			getTrace().addInfo(headerdesc);
//orginal response was coming after <responseBase64> tag which is capture here
			responsebase64 = responsebase64.substring(responsebase64.indexOf("<responseBase64>") + 16);
			
			getTrace().addInfo(responsebase64);
			
//I am checking here if response is there or not, if not i am making a custom xml
			if ( responsebase64.indexOf("</responseBase64>") == 0)
			{

				isFound = "N";
			}
			else
			{
				responsebase64 = responsebase64.substring(0, responsebase64.indexOf("</responseBase64>"));
				isFound = "Y";
			}
				
				
			getTrace().addInfo("truecheck" + isFound + responsebase64);
			if ( isFound == "Y" ) 
			{
				getTrace().addInfo("ifcheck");
				org_msg = org_msg.substring(org_msg.indexOf("<responseBase64>") + 16);
				org_msg = org_msg.substring(0, org_msg.indexOf("</responseBase64>"));
				getTrace().addInfo("beforedecoding" + org_msg);
				byte[] decodedBytes = Base64.getDecoder().decode(org_msg);
				getTrace().addInfo("decoded");
				String decodedString = null;
				// Get the string of decoded byte array
				String s = new String(decodedBytes);
//		  String encrypted = "";
				decodedString = s;

				getTrace().addInfo("beforedecryption");
//this is the decryption code, you can use it based on ur use case
				originalFileName = pgp.decryptString(decodedString, privateKeyFile, privateKeyPassword);
//end of decryption code
				getTrace().addInfo("decrypted" + originalFileName);
			}
			
			else 
			
			{
				getTrace().addInfo("elsecheck");
				String so = originalFileName;	
				if (so == "") {
///if the code is blank					
					originalFileName = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
							+ "<ns0:Document xmlns:ns0=\"urn:http://x.com\">\r\n" + "<paymentresponseBase64>"+"FAILED"+"</paymentresponseBase64>"

+ "</ns0:Document>";
				}
			}
			String target_msg = originalFileName;
			getTrace().addInfo("finalstructure" + target_msg);
			outputstream.write(target_msg.getBytes());

		}

		catch (Exception ie) {
		}
	}
}​

 

 

Note:
I have used the above code based on my use case, you can play around with the Didisoft libraries and choose what fits best. For the adapter level, many modules and blogs are available that can be used to do the encryption and decryption.
Keep track of the expiry of keys, would be helpful for you as a change in year-end activity.

 

Labels in this area