Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
sunny_kapoor
Advisor
Advisor
In one of my proof of concept work, the requirement was to decrypt a XML payload using SAP Cloud Integration. This XML payload is encrypted as per the W3C Recommendation i.e. XML-Signature Syntax and Processing, W3C Recommendation 12 February 2002 and XML Encryption Syntax and Processing, W3C Recommendation 10 December 2002

XML is encrypted using the SECXML_XENCRYPTION  standarad executable ABAP Report with the following specification:

  • AES256-CBC algorithm to encrypt data

  • RSA v1.5 algorithm to encrypt the AES key


 

Encrypted XML:
<Person xmlns:nm="http://www.sap.com/saphr/person/1_0" xmlns:prx="urn:sap.com:proxy:HP1:/1SAI/TASC1D8B7EB3CD3DF9DE517:731">
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<xenc:EncryptedKey Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<xenc:CipherData>
<xenc:CipherValue>Ib7QIaQ1fA5EA2GAaoai8LEK47b7An3eoDESS7VWnjL+CBJqe9t97HeSuJZCYsVRSmBvRNy4yc1C6G80KOt30+mi2+N7TS9xcdVXfHJGAfmVkshKgJkca7w4kH2jBFspMtn4XopNZZHdFedRXoFZgQ5smaOHfutWdBOJBBWsnQ5bNPwG9NHDhs44pDEGOfTFJFFW8/RodqvyaLChHUR3FxxQmuoEtlX5CRd1+3FSJbWfLtk21EysuBcBBZSwFMtEp4YvMgXRKaE13HgUzxKMpho6LPxI69+wBmUPZCZcc/K9J0LfcJA+Q3DN+lSZEDwPfMNT77Qli9XskOjkt1HIsA==</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedKey>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>uAd59MSd+3+lutSPgP1rWIpE02erC8uIV7V3+Db0ePy5qQdmmbg9q5HpgTH2rZDEChdwg4gLhIQtYP8qyN3DdxMrMBgysRdNl3ka+h22nfPAgQXrGGoJgDph4nnD27UEG3DWbeQrQxaN29S75DnvPfP+NLvN+trSrrkY7Ew7YY+QMAfbWrazGTT06bQIZLN6hDJv2HaGWa05aAcAR9b0yD0wuTDI+t2tfhyD+jB9w76h9ar/17tZRuUNETeg12hutoNkKjDsnNuttUJrEGYgMDusyVdGt/3lYCAKhZzxpyk5OnTQ2zXDfmlzl5Z2w6vkiBMtnst3DhYm5NdFxxSQ9B/ctdLU32GnHo8wgnvAY6mYr378HZVhtAUz5vP+lLFjDrHqGoTn3F+IYV3DA1qyCNI8c5iY56ZwaSH9Lh3JUBLRO2SRYWSLTgv3FrZV/jyXiUUhAhjYbIudi0gyGAQ8lNrFZE2NME34U7N1Q2eZbaXHPzcC8zamJD992wkA1yFueR/29rEP8PldnOJ1PcG2PoeIvMCXADG5gskMjyIzzmoousZOugCM1l/6GlLvTAi9bGYI+uH+iCTh6RME4wp/zV3LfgfzoUOTdkNY5sObiMruEsfKNri3PEW+8egzNIVWkrje/2thunXjtmssW6PkA290A51RWYZben/TIyltPu/akLQ2W6GlrRHLp+hZlrae</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</Person>

 

Solution:

As there is no encryption/decryption flow step in Cloud Integration for XML messages, there are two possible solution to decrypt the above XML using SAP Cloud Integration:

  1. Use a Groovy Script flow step with standard JAVA JCE/JCA Classes.

  2. Use a Groovy Script flow step with third party jar i.e. Apache Santuario . The Apache XML Security for Java library supports XML-Signature Syntax and Processing, W3C Recommendation 12 February 2002 and XML Encryption Syntax and Processing, W3C Recommendation 10 December 2002.


The advantage of using Apache Santuario jar is, it is written as per the W3C recommendation, so you only need to pass the Encrypted XML, it automatically finds the encrypted key + algorithm and encrypted data + algorithm to give you the final decrypted XML.

Where as in 1st solution, we need to find the encrypted key first, decrypt it and then use the decrypted key to decrypt the data and finally append it to the original XML structure. But this approach do not require any external jars.

In this blog, first solution is used.

Integration Flow:



As you can see in the above screenshot, we receive the encrypted XML payload via SOAP adapter then log the payload and finally send the payload to XML Decryption groovy script flow step to get the decrypted XML.

The algorithm to decrypt the XML with standard JAVA JCE/JCA Classes is as follows:

  1. To decrypt the AES key which is encrypted via RSA algorithm, first we need to get the private key pair from the Cloud Integration keystore.

  2. Then extract the encrypted AES key and AES Data(Encrypted XML) from the given XML.

  3. Decrypt the AES Key string using the private key which we got in step 1.

  4. Decrypt the AES Data string(Encrypted XML) using the AES key which we got in step 3.

  5. Append the Decrypted XML to the original XML Structure.


XML Decryption Groovy Script:
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import com.sap.it.api.ITApiFactory;
import com.sap.it.api.keystore.KeystoreService;
import java.security.cert.Certificate;
import java.security.KeyPair;
import java.security.PrivateKey;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.codec.binary.Base64;
import groovy.xml.Namespace;
import groovy.util.XmlParser;
import groovy.xml.XmlUtil;

def Message processData(Message message) {
KeystoreService service = ITApiFactory.getApi(KeystoreService.class, null);
Certificate cert = service.getCertificate("rover");
KeyPair keypair = service.getKeyPair("rover");
PrivateKey privateKey = keypair.getPrivate();

//Body
def body = message.getBody(java.lang.String) as String;
def person = new XmlParser(false,false).parseText(body);

def xencns = new groovy.xml.Namespace("http://www.w3.org/2001/04/xmlenc#",'xenc')
def dsns = new groovy.xml.Namespace("http://www.w3.org/2000/09/xmldsig#",'ds');

String encryptedAESKey = person[xencns.EncryptedData][dsns.KeyInfo][xencns.EncryptedKey][xencns.CipherData][xencns.CipherValue].text();
String encryptedXMLData = person[xencns.EncryptedData][xencns.CipherData][xencns.CipherValue].text();

SecretKey aes_key = decryptAESKey(encryptedAESKey, privateKey);
String decryptedXMLData = decryptAESData(encryptedXMLData, aes_key);

decryptedXMLData = "<root>" + decryptedXMLData + "</root>";

def childNode = new XmlParser(true,true).parseText(decryptedXMLData);

person[xencns.EncryptedData].replaceNode{};

childNode.each{child ->
person.append(child);
}

def messageLog = messageLogFactory.getMessageLog(message);
messageLog.addAttachmentAsString("Certificate", cert.toString(), "text/plain");
messageLog.addAttachmentAsString("Encrypted AES Key", encryptedAESKey, "text/plain");
messageLog.addAttachmentAsString("Encrypted XML Data", encryptedXMLData, "text/plain");
messageLog.addAttachmentAsString("Decrypted AES Key", aes_key.getEncoded().toString(), "text/plain");
messageLog.addAttachmentAsString("Decrypted XML Data", decryptedXMLData, "text/plain");

message.setBody(XmlUtil.serialize(person));
return message;
}

SecretKey decryptAESKey(String encryptedAESKey, PrivateKey privateKey){
byte[] decryptedAESKey = null;
SecretKey aes_key = null;
try {
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// decrypt the text using the private key
cipher.init(Cipher.DECRYPT_MODE, privateKey);

decryptedAESKey = cipher.doFinal(Base64.decodeBase64(encryptedAESKey));
aes_key = new SecretKeySpec(decryptedAESKey, "AES");
} catch (Exception e) {
throw new Exception(e.getMessage());
}

return aes_key;
}

String decryptAESData(String encrypted, SecretKey key) {
int ivLen = 16;
byte[] ivBytes = new byte[ivLen];
byte[] encryptedBytes = Base64.decodeBase64(encrypted);
System.arraycopy(encryptedBytes, 0, ivBytes, 0, ivLen);
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

Cipher cipher = Cipher.getInstance("AES/CBC/ISO10126Padding");

cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);

String decrypted = new String(cipher.doFinal(encryptedBytes, ivLen, encryptedBytes.length - ivLen));

return decrypted;
}

 

SOAP Request:



SOAP Response:

6 Comments