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
rhviana
Active Contributor
Hi sunny.kapoor2

First of all Xmas for you and thanks for such nice blog.

I would like to ask something, I will need also to produce POC for encryption and sign XML using CPI standard functions:

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



Why you could not used it instead of go for custom solution using groovy.

I was not able to check those functionalities but I tired in the past produce POC using the SOAP adapter with encrypt and sign and not works proper with SAP PO.

Thanks and happy new year.

Viana.
sunny_kapoor
Advisor
Advisor
0 Kudos

Hi ricardo.viana

Kindly excuse me for replying you late on this.

As I have mentioned in the blog, there is a specification for XML Encryption/Decryption from W3C

XML Encryption Syntax and Processing, W3C Recommendation 10 December 2002

As of today there is no flowstep in CPI which understand the encrypted XML and can encrypt/decrypt the XML payload as per the specification.

In an existing example the XML data is encrypted via AES256-CBC symmetric algorithm, where key is encrypted via RSA - asymmetric algirthm and is part of the XML payload itself.

You can encrypt the entire XML or part of it.

PGP and PKCS7 decryptor do not understand the encrypted XML specification and syntax and therefore cannot be used.

Where as Signer is used for creating a digital signature and has a different concept and usage than encryption.

Kindly go through the specification to understand this in detail.

I hope this will help.

 

Regards,
Sunny

0 Kudos
Hi Sunny,

 

Can you please let us know the Ciphers suites supported by SAP CPI Neo?

Regards
0 Kudos
Hi Sunny,

Thanks for your blog. But my scenario is different. I am getting the input as XML payload and need to sign the complete XML messages. I used PKCS7 signer and encrypter but none of them seems to be working.

Kindly help me with the scenario and also let me know further information needed.

 

Regards,

Nisha.
joel_langoyan
Participant
0 Kudos
hi sunny.kapoor2,

I have similar requirement but it is for SAP PO. My input XML is encrypted in 3DES instead of AES. I encounter java.security.InvalidKeyException: Wrong key size on cipher.init for start of decrypting the encrypted data. I'm not sure what I need to change to get the right Key size. Please help.
int ivLen = 8;
byte[] ivBytes = new byte[ivLen];
byte[] encryptedDataBytes = Base64.getDecoder().decode(encData.getTextContent());
System.arraycopy(encryptedDataBytes, 0, ivBytes, 0, ivLen);

IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipherData = Cipher.getInstance("DESede/CBC/NoPadding");
cipherData.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
String decryptedData = new String(cipher.doFinal(encryptedDataBytes, ivLen, encryptedDataBytes.length - ivLen));
System.out.println("DEcrypted Data: "+decryptedData);

 
sunny_kapoor
Advisor
Advisor
0 Kudos
Hi joel.langoyan,

Sorry, But I would not of much help here. I suggest you to make it work in an independent program and then try to port in SAP PO.

Regards,

Sunny