Skip to Content
Technical Articles

How to encrypt/decrypt XML payload with AES256-CBC and RSA Algorithm in SAP CPI

In one of my proof of concept work, the requirement was to decrypt a XML payload using SAP CPI. 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 CPI for XML messages, there are two possible solution to decrypt the above XML using SAP CPI:

  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 CPI 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:

1 Comment
You must be Logged on to comment or reply to a post.
  • Hi Sunny Kapoor,

    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.