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: 
CarlosRoggan
Product and Topic Expert
Product and Topic Expert
SAP Cloud Integration (aka CPI) supports encryption based on international standards like CMS (PKCS #7) and PGP.
However, there are use cases where a message should be just simply encrypted, such that CMS or PGP is not required at receiver side.
This blog post shows how to achieve that with a simple groovy script.

Quicklinks:
Sample Code



Content


0.1. Prerequisites
0.2. Introduction
0.3. Create Key Pair
1. Scenario 1: Simple Encryption
1.1. Create iFlow
1.2. Run iFlow
1.3.Local Decryption with OpenSSL
1.4. Decrypt in iFlow
2. Scenario 2: Simple Sign and Encrypt

2.1. Create iFlow
2.2. Run iFlow
2.3.Local Decryption and Verification with OpenSSL
2.4. Decrypt and Verify in iFlow
3. Optional: Providers and Transformations
Appendix 1: Groovy Script for Encryption
Appendix 2: Groovy Script for Decryption
Appendix 3: Groovy Script for Verification
Appendix 4: Groovy Script for Providers
Appendix 5: Sample Config for OpenSSL

0.1. Prerequisites


🔷 CPI
To follow this tutorial, access to a Cloud Integration tenant is required, as well as basic knowledge about creating iFlows.

🔷 OpenSSL
This tutorial uses OpenSSL to generate a key pair and to locally decrypt + verify the iFlow-message

Install OpenSSL
OpenSSL is the most commonly used tool (and library) for security-related operations, dealing with certificates, keys, converting, etc etc
Basically, it consists of libraries (for “c”) and a command line tool.
If you have GIT installed, you can just open the git bash which contains openssl.
Otherwise, follow these instructions to install OpenSSL under Windows:

Download openssl starting from here.
Afterwards it might be required to add the openssl.exe to the PATH.
If you get this error:
Unable to load config info from /usr/local/ssl/openssl.cnf
You need to set an environment variable.
e.g. on command line:
set OPENSSL_CONF=c:/tools/openssl/openssl.cfg

Note:
For windows, the config-file extension .cnf has to be adjusted to .cfg
A template .cnf file can be found in GIT installation folder (e.g. at \mingw64\ssl) or in the appendix 5.

0.2. Introduction


When sending sensitive messages over the internet from a sender to a recipient, it is recommended  to apply cryptographic protection ("message -level security" in CPI).
In addition to the encrypted message content, it is required to send information to the receiver about how to decrypt the message (which algorithm etc).
This is one reason, why the standard “Cryptographic Message Syntax” (CMS) was defined.
Following this standard, all required information is added to the message in a structured way, thus enabling safe message plus metadata transfer.
To encrypt or sign and create and package the metadata and artifacts (e.g. keys) altogether, special libraries and tools are required.
Thanks to SAP Cloud Integration and its CMS-steps, it is easy to use.

But what if the receiver doesn’t have the required tools to support CMS?
Or if using CMS would add too much overhead if sender and receiver are well known to each other?
Cloud Integration offers a “Simple Signer” but no “Simple Encryptor”.

This tutorial provides the solution:
It shows how to apply simple encryption to a message in a groovy script.
Furthermore,  it shows how such a programmatically encrypted message can be decrypted.
Decryption is shown in 2 ways:
🔸Via Groovy script
🔸Via command line with OpenSSL on local machine

This blog post covers 2 scenarios:

🔸Scenario 1:
Encrypt a message in an iFlow
Decrypt it
🔸Scenario 2
Sign and encrypt a message in an iFlow
Decrypt and verify it

For encryption and signature, a key pair is required.
BTW, we're not using the CPI Keystore dashboard to generate a key pair, because for local processing, we need the key pair on our machine.

Security Consideration
It is essential to discuss how to treat the private key used to encrypt or sign.
The CMS standard uses symmetric key to encrypt the message content.
This means that the same key must be present on receiver side.
As it is not safe to transfer a key, the key itself is encrypted via asymmetric encryption.

In our simplified use case, we have to consider the same.
Symmetric encryption is faster but for us it is too unsafe to send the key to the receiver.
So we’re using asymmetric encryption in our tutorial.
However, with private key it is same: we have to make sure that it is kept in a safe place and doesn’t need to be sent around.

Disclaimer:
This blog post doesn’t represent an official documentation nor recommendation.
Actually, myself I wouldn’t recommend to go for the manual way.
I’m posting as my own learning after it was asked for, by a user of CPI.

Now we can get started.

0.3. Create Key Pair


For the cryptographic operations, we need a key pair.
it has to be wrapped by a p12 file for uploading to CPI.

1. Create key pair and certificate

Below req command creates a key pair and a self-signed certificate in one step.
openssl req -x509 -newkey rsa -nodes -keyout privkey.pem -out cert.pem -subj "/CN=simplecert"

Note:
When copy- and pasting the command under windows, it might be required to clean the formatted quotation marks.

Info:
The req command is typically used for CSRs (certificate signing requests) according to PKCS #10, but it supports parameters for generating certificates as well.
-x509 this flag is responsible for generating a certificate.
-newkey generates a private key with algorithm “RSA”. We don’t specify the key size here, we can rely on the default, which is 2048.
-nodes not encrypt the private key.
-out the name of the generated certificate. The file extension can be chosen as of our taste.
-subj here we can pass the attributes of the certificate, like CN (common name) in our example. Other attributes may be specified here, but we leave them, to make it more simple.

2. Extract public key

For the "verify" command, we need the public key, which can be extracted from the private key with pkey command:
openssl pkey -pubout -in privkey.pem -out pubkey.pem

Info:
-pubout is used to write the public key

3. Create p12/pfx file

To create a container, we use the pkcs12 command of OpenSSL.
The pkcs#12 standard defines a binary format to store certificates (etc), protected with password and thus suitable for import/export.
openssl pkcs12 -export -out simplestore.p12 -inkey privkey.pem -in cert.pem -name simplestore -passout pass:abcd

Info:
The pkcs12 command uses 2 input parameters to specify the certificate and private key that should be stored in the .p12 result file.
-export is used to generate a .p12 file (instead of operating on an existing one).
-passout allows us to specify a password, as the PKCS #12 standard supports password to protect the stored private key.
-out we specify the result file with the usual .p12 file extension. Another common file extension would be .pfx.
-name gives an alias which will be displayed in CPI Keystore

4. Upload to CPI Keystore

In your CPI dashboard, go to "Monitoring" -> "Keystore" and choose "Add"->"Keystore".
Browse for the .p12 file and enter the password, as provided in the command: "abcd".
Remember the Alias name ("simplestore") for later use.

1. Scenario 1: Simple Encryption


In our first scenario we want to just encrypt a message, with simple RSA-based asymmetric encryption.

1.1. Create iFlow


We create a simple demo iflow that creates some dummy text in a content modifier step and then encrypts it via Groovy script.
The required public key is fetched from the CPI Keystore via API call.
After encryption, we store the encrypted message in a Data Store, such that we can grab it for local decryption.
However, as we want to show how to decrypt in a Groovy script, we just continue the iFlow and add a second Groovy script for decryption.
To check if the decryption was successful, we write it to the log, at the end of the second groovy script.


To avoid confusion, let’s briefly go through the iFlow elements:

🔸Start Timer
Set to “Run Once”. 
🔸Content Modifier
Message Body with some arbitrary text.
🔸Groovy Script 1
Code for encryption copied from Appendix 1.
🔸Data Store Write
Data Store Name set as any name of our choice.
🔸Groovy Script 2
Code for encryption copied from Appendix 2.

The Groovy Script for Encryption

The steps we’re doing in our script

  1. get the message as byte array

  2. Access the public key

  3. encrypt

  4. base64 encode

  5. set the message


Let’s have a look:

1. Get the message body and convert to byte array
def body = message.getBody() as String;
byte[] bodyAsBytes = body.getBytes();

2. Fetch the public key from CPI Keystore

Note that the name that is hard-coded in this snippet needs to be adapted in case you’re using a different name.
KeystoreService keystoreService = ITApiFactory.getService(KeystoreService.class, null)
KeyPair keyPair = keystoreService.getKeyPair("simplestore");
PublicKey publicKey = keyPair.getPublic();

3. Encrypt

We’re using the javax.crypto library for our encryption task.
We’re initializing it with the transformation  "RSA/ECB/PKCS1Padding".
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

Note
This can be adapted as of your needs, as long as it is supported by the runtime.
Note
All 3 segments of a transformation should be provided, otherwise defaults are used and we don’t know how to decrypt afterwards.

The 3 segments stand for:
algorithm
operation mode 
padding scheme

Examples:
AES/CBC/PKCS5Padding (128)
DESede/ECB/NoPadding (168)
RSA/ECB/PKCS1Padding (1024, 2048)

The values in parentheses are referring to key sizes.
In my CMS-Encryptor blog post, I’ve tried to explain a bit in my simple words.

What are the possible values that we can enter as transformation?
The answer can be found in the optional chapter at the end.

We configure the cipher instance with the public key and the message content that should be encrypted.
Finally do the actual encryption:
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipher.update(bodyAsBytes);
byte[] encryptedMsg = cipher.doFinal();

4. Base64 encoding

The result of the encryption is an array of bytes, which is not recommended for transferring via the network. It could cause problems, related to special characters that might get lost if transport protocol doesn’t handle properly.
When encoding with Base64, we’re on the safe side, because the character set that is used to transfer the message contains only normal characters (alphabet upper and lower case, numbers and 3 others => 64).
def encodedMsg = Base64.getEncoder().encodeToString(encryptedMsg);

The difference between encrypting and encoding:
Encryption makes the data un-understandable.
Encoding just transforms the data into different format.
Decryption requires secret password or key.
Decoding is open and can be done by everybody.

5. Set message

Finally, we replace the message body with our encrypted and encoded content:
message.setBody(encodedMsg);
return message;

The full script can be found in the appendix 1.

1.2. Run iFlow


We can save & deploy our iFlow.
The iFlow is started by the timer and a new Data Store with our specified name is accessible at “Monitor-> integrations -> Manage Stores -> Data Stores
We select the new entry, download it and extract to the same directory where we’ve created our private key (chapter 0.3.)

1.3. Locally Decrypt with OpenSSL


We open our command prompt at the directory which contains the private key and the extracted file with name body.

Base64-Decode

First of all, we need to decode the content, as we’ve Base64-encoded it at the end of our Groovy script:
openssl enc -base64 -d -in body -out body_enc

Above command specifies the “decode” operation via -d option and writes the decoded content (which is encrypted) into a file called body_enc.

Note:
If the operation doesn’t work and results in an empty file, as in my case, we need to apply the following solution:
Open the file, place the cursor at the very end and hit <Enter>, to add a line break.

Decrypt

To decrypt the content, we use the pkeyutl command which requires our private key and writes a new file containing the plaintext message.
The options parameter allows to specify information about the used transformation. This must match the transformation used during encryption.
openssl pkeyutl -decrypt -in body_enc -inkey privkey.pem -out body_plain -pkeyopt rsa_padding_mode:pkcs1

After successful decryption we can open the body_plain file and check that the content is indeed the same as we specified in the content modifier step.

1.4. Decrypt in iFlow


In order to support users who aren’t interested in OpenSSL, we've added a Groovy script to show some code.
Obviously, it doesn’t make much sense to add the decryption in the same iFlow, but it makes things easier.

The Groovy Script for Decryption

The code is very similar to the encryption script, just in inverse order.
The steps are:

  1. Access message

  2. Base64-decode

  3. Access Private Key

  4. Decrypt

  5. Set message content


Let’s just quickly point to the differences.

First of all. decoding is necessary as the message was base64-encoded in the previous script:
byte[] bodyEncrypted = Base64.getDecoder().decode(body);

For decryption we need the private key, accessed from the same uploaded key pair:
KeyPair keyPair  = keystoreService.getKeyPair("simplestore");
PrivateKey privateKey = keyPair.getPrivate();

The cipher instance has to use the same transformation info, but this time used for decryption:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);

To view the result of decryption without writing into another data store, let’s just write it into the log:
def messageLog = messageLogFactory.getMessageLog(message);
messageLog.addAttachmentAsString("Result", "Result of decryption: " + new String(decrypted), "text/plain")

The full script can be found in the appendix 2.

After running the iFlow, we can find the result in the Monitoring section at
Monitor -> Integrations -> Monitor Message Processing
Select entry of iFlow and head over to the Attachments where an attachment with name “Result” should be available.

2. Scenario 2: Simple Signature and Simple Encryption


This time, we want to add a simple signing step in addition to the already implemented simple encryption.
SAP Cloud Integration already offers a “Simple Signer” step which we can use for this purpose.
However, when it comes to verify the simple signature in the iFlow, we need another Groovy script, as CPI doesn’t offer a “Simple Verifier”.
For this purpose, we can reuse the script that I published in this blog post.

2.1. Create iFlow


For the second scenario, we can reuse the existing iFlow, as we just want to add the signing capability.

Note
My design is based on the assumption that a signature should be created first, on the plaintext content, not on the encrypted content.
There might be different opinions and use cases.

So coming to the existing iFlow, we have to change it as follows:
1. We add a “Simple Signer” step after the content modifier and before the first Groovy Script.
2. We mark a checkbox of the existing Data Store step.
3. And we add a third Groovy script after the second one, at the end of the iFlow


To avoid confusion, let’s briefly go through the iFlow elements:

🔸Start Timer
No change. 
🔸Content Modifier
No change.
🔸Simple Signer
Add "Simple Signer" step from "Security" in Palette.
Private Key Alias name: "simplestore".
Signature: "SHA512/RSA".
Signature Header Name: leave the default "SAPSimpleSignatureValue".
🔸Groovy Script 1
No change.
🔸Data Store Write
This change is relevant:
Set the checkbox for "Include Message Headers" to enabled.
🔸Groovy Script 2
No change.
🔸Groovy Script 3
Add step for Groovy Script at the end of the iFlow.
Code for verification copied from Appendix 3.

This iFlow combines simple signing and encrypting capabilities.
Let's see if we can decrypt and verify afterwards...

2.2. Run iFlow


After save & deploy our iFlow, we download the new data store entry to our local directory.
We extract the zip file, this time we need both, the body and the headers.prop file

2.3. Locally Decrypt and Verify with OpenSSL


We open the headers.prop file and find the header “SAPSimpleSignatureValue” and the value which is the base64-encoded signature.
We delete all content from this file and leave only the signature.
If the signature contains escape characters (\), we remove them as well:


So at the end, the headers.prop file looks like this:


Note:
On my machine (win), it was necessary to add a line break at the end of the string (just press Enter), otherwise the openssl command doesn’t work.

After preparing the 2 downloaded files, we can go ahead, decrypt and verify the signature with OpenSSL

We open our command prompt at the directory which contains the private key and the extracted files.

Base64-decode the message body

First of all, we need to decode the content, as we’ve Base64-decoded it at the end of our Groovy encryption script:
openssl enc -base64 -d -in body -out body_enc

Decrypt the message body
openssl pkeyutl -decrypt -in body_enc -inkey privkey.pem -out body_plain -pkeyopt rsa_padding_mode:pkcs1

Base64-decode the signature
openssl enc -base64 -d -in headers.prop -out signa_enc

Verify the signature
openssl dgst -verify pubkey.pem -sha512 -signature signa_enc body_plain

Result should be: a success message printed to the console

2.4. Decrypt and Verify in iFlow


As we’ve already created the third Groovy script for verifying the signature, we can now have a quick look at the script.

The steps are:

  1. Access message

  2. Access Public Key

  3. Access Signature

  4. Base64-decode signature

  5. Verify signature

  6. Log verification result


The Groovy Script for Verification

I’m just copy and pasting the script from this blog post.
I you’re wondering why I’m not ashamed of stealing code…..
!I’m the author hihi)

The code-copy needs to be adapted only for
- The alias of the key par
- The name of the signature header of Simple Signer, in case that it was changed

After disclosing the origin of the code – I’m now too lazy to explain the procedure.
May I ask you to consult this section for details?
    def body = message.getBody(java.lang.String) as String;
byte[] bodyAsBytes = body.getBytes();

// Public Key
KeystoreService keystoreService = ITApiFactory.getService(KeystoreService.class, null)
KeyPair keyPair = keystoreService.getKeyPair("simplestore");
PublicKey publicKey = keyPair.getPublic();

// Signature
def signature = message.getHeaders().get("SAPSimpleSignatureValue");
byte[] signatureAsBytes = Base64.getDecoder().decode(signature);

// Verify
Signature sig = Signature.getInstance("SHA512withRSA", "SunRsaSign");
sig.initVerify(publicKey);
sig.update(bodyAsBytes);
boolean verificationResult = sig.verify(signatureAsBytes);

// Handle result
def messageLog = messageLogFactory.getMessageLog(message);
messageLog.addAttachmentAsString("VerificationResult", "Verification result: " + verificationResult, "text/plain");
if(! verificationResult) throw new Exception("Verification of Digital Signature failed!")

The full script can be found in the appendix 3.

After running the iFlow, we can find the result in the Monitoring dashboard, where we can open the attachment with name “VerificationResult”.
It should contain our log entry for successful verification.

Troubleshooting


I ran into following isses:

🔸Error during decryption with OpenSSL

Error message:
ERROR: RSA_padding_check_PKCS1_type_2 error
Reason:
This error message can be misleading. One simple reason for this error can be:
Using a different key pair in iFlow and command line.
Solution:
Make sure to locally use the same key pair like the one that was uploaded to CPI
Check the key pair name in all Groovy scripts and in the “Simple Signer” step.

🔸Problems on local command line

Error:
After downloading and extracting the body and header file from Data Store, the files aren’t properly processed by OpenSSL.
Reason:
CPI doesn’t seem to add a Line Break after writing the (encoded) message to the data store, or header file.
OpenSSL doesn’t seem to be able to work on a file whose content is not finalized with line break.
Solution:
Open the file and manually add a line break at the end, after last character

🔸Problem with algorithm

Error:
java.security.NoSuchAlgorithmException: Cannot find any provider supporting ...
Reason:
In the Groovy script, while initializing the Cipher instance, a transformation was requested that is not supported.
Solution:
Check which transformations are possible via the script in chapter 3

3. Optional: Providers and Transformations


While going through the Groovy code in chapter 1.1. we were all wondering about the mystic transformation that has to be entered as a string:
"RSA/ECB/PKCS1Padding"
Transformation stands for the transformation that is done with the input string.
It is transformed into some silly bytes that nobody can understand.
To make it as un-understandable as possible, there are several mechanism that can be used, all in one string:

1. First, the name of the cryptographic algorithm (algorithm = cipher)
Example: RSA
RSA is an asymmetric algorithm, which means that a key pair (asymmetric encryption) is required.
Alternatively, a symmetric algorithm like AES could be specified.

2. Second, the operation mode
Example: ECB which stands for Electronic Code Book.

* Third, the padding scheme
Padding means to add some bytes to the beginning or end of a message in order to fill up blocks and add another level of security.
Example: PKCS1Padding

To get the list of all possible algorithms and transformations, we need to consult the Java Security library at runtime.
Reason is that there are so many algorithms and implementations that the architecture of Java Security must be open to allow further implementations.
These pluggable implementations are called “Providers”.
There are some standard transformations that are listed in the Java documentation.
Nevertheless, we have to use a little code snippet to see which transformations are available on CPI runtime and which providers are supporting it.
Below code snippet lists the algorithms available, filtered for encryption (other filter could be e.g. "signature")
StringBuffer text = new StringBuffer();
Provider[] providers = Security.getProviders();

for (Provider provider : providers) {
text.append("\nProvider: " + provider.getName());
Set<Service> services = provider.getServices();
for(Service service : services) {
if(service.getType().equals("Cipher")) {
text.append("\n Supports algorithm: '" + service.getAlgorithm() + "'");
}
}
}

See appendix 4 for full Groovy script.

Note
We don’t need to deploy. We can get the result in simulation mode (as the result is written to message body).

Summary


In this tutorial we’ve learned how to programmatically encrypt a message with Groovy.
It is the most simple way of encrypting with asymmetric cryptography (means: using key pair).

We’ve also learned how to decrypt a message, both with Groovy and with OpenSSL.

In a second step, we’ve also added simple signing and verifying capabilities to our example iFlow.

Using this simple manual way of encrypting is not recommended and only required if the standard way, CMS, cannot be used.

Links


Blogs on the cryptographic support of CPI:
Understanding the PKCS #7 / CMS standard
Understanding the PKCS #7 / CMS Encryptor
Understanding the Simple Signer
And the Security Glossary Blog.

OpenSSL
Official list of unofficial binaries download page
Docu home
Manual: https://www.openssl.org/docs/manmaster/man1/
req: https://www.openssl.org/docs/manmaster/man1/openssl-req.html
pkcs12: https://www.openssl.org/docs/manmaster/man1/openssl-pkcs12.html
pkey: https://www.openssl.org/docs/manmaster/man1/openssl-pkey.html
pkeyutl: https://www.openssl.org/docs/manmaster/man1/openssl-pkeyutl.html
decode: https://www.openssl.org/docs/manmaster/man1/openssl-enc.html
digest: https://www.openssl.org/docs/manmaster/man1/openssl-dgst.html

SAP Help Portal
Docu for Simple Signer
Javadoc for Groovy scripting main entry

Javadoc
Standard Algorithm names
Cipher class




Appendix 1: Groovy Script for Encryption


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.KeyPair;
import java.security.PublicKey;
import javax.crypto.Cipher;


def Message processData(Message message) {

// get nessage as byte array
def body = message.getBody() as String;
byte[] bodyAsBytes = body.getBytes();

// fetch the public key from CPI Keystore
KeystoreService keystoreService = ITApiFactory.getService(KeystoreService.class, null)
KeyPair keyPair = keystoreService.getKeyPair("simplestore");
PublicKey publicKey = keyPair.getPublic();

// Encrypt
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
// Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// byte[] input = "Dummy text".getBytes();
cipher.update(bodyAsBytes);
byte[] encryptedMsg = cipher.doFinal();

// base64-encode the encrypted message
def encodedMsg = Base64.getEncoder().encodeToString(encryptedMsg);

message.setBody(encodedMsg);
return message;
}

Appendix 2: Groovy Script for Decryption


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.KeyPair;
import java.security.PrivateKey;
import javax.crypto.Cipher;


def Message processData(Message message) {

// read and decode message that comes base64-encoded
def body = message.getBody(java.lang.String) as String;
byte[] bodyEncrypted = Base64.getDecoder().decode(body);

// Private Key
KeystoreService keystoreService = ITApiFactory.getService(KeystoreService.class, null)
KeyPair keyPair = keystoreService.getKeyPair("simplestore");
PrivateKey privateKey = keyPair.getPrivate();

// Decrypt
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
cipher.update(bodyEncrypted);
byte[] decrypted = cipher.doFinal();

// log result
def messageLog = messageLogFactory.getMessageLog(message);
messageLog.addAttachmentAsString("Result", "Result of decryption: " + new String(decrypted), "text/plain")

// set message body
message.setBody(new String(decrypted));
return message;
}

Appendix 3: Groovy Script for Verification


import com.sap.gateway.ip.core.customdev.util.Message;
import com.sap.it.api.ITApiFactory;
import com.sap.it.api.keystore.KeystoreService;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.Signature;


def Message processData(Message message) {

// Content
def body = message.getBody(java.lang.String) as String;
byte[] bodyAsBytes = body.getBytes();

// Public Key
KeystoreService keystoreService = ITApiFactory.getService(KeystoreService.class, null)
KeyPair keyPair = keystoreService.getKeyPair("simplestore");
PublicKey publicKey = keyPair.getPublic();

// Signature
def signature = message.getHeaders().get("SAPSimpleSignatureValue");
byte[] signatureAsBytes = Base64.getDecoder().decode(signature);

// Verify
Signature sig = Signature.getInstance("SHA512withRSA", "SunRsaSign"); // algorithms and the provider. "SunRsaSign" is a built-in provider that supports RSA
sig.initVerify(publicKey);
sig.update(bodyAsBytes);
boolean verificationResult = sig.verify(signatureAsBytes);

// Handle result
def messageLog = messageLogFactory.getMessageLog(message);
messageLog.addAttachmentAsString("VerificationResult", "Verification result: " + verificationResult, "text/plain");
if(! verificationResult) throw new Exception("Verification of Digital Signature failed!")

return message;
}

Appendix 4: Groovy Script for Providers


import com.sap.gateway.ip.core.customdev.util.Message;
import java.security.Security;
import java.security.Provider;
import java.security.Provider.Service;


def Message processData(Message message) {

StringBuffer text = new StringBuffer();
Provider[] providers = Security.getProviders();

for (Provider provider : providers) {
text.append("\nProvider: " + provider.getName());
Set<Service> services = provider.getServices();
for(Service service : services) {
if(service.getType().equals("Cipher")) {
text.append("\n Supports algorithm: '" + service.getAlgorithm() + "'");
}
}
}

// print Groovy version
text.append("\n");
text.append("\nCurrent Groovy version: " + GroovySystem.version);

// write result to log
def messageLog = messageLogFactory.getMessageLog(message);
messageLog.addAttachmentAsString("Provider_Info", text.toString(), "text/plain");

// write result to message body
message.setBody("Provider Info: \n" + text.toString())
return message;
}

Appendix 5: Sample Config for OpenSSL


[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[ req_distinguished_name ]
C = DE
L = Walldorf
O = Cloud
OU = integration
CN= simplesignernode
emailAddress = simplesign@iflowtonode.com

[ v3_req ]
basicConstraints = CA:false
keyUsage = nonRepudiation, digitalSignature
subjectKeyIdentifier=hash