Technology Blog Posts 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: 
Sunil_Pharswan
Explorer
2,520

In today's data-driven world, securing sensitive information is crucial. RSA (Rivest-Shamir-Adleman) is a widely used encryption algorithm that ensures data security by encrypting and decrypting information using a pair of public and private keys. In this blog, we'll discuss the technical aspects of RSA encryption, including how to handle the limitation of data size with RSA/ECB/PKCS1Padding, and walk through the integration process steps for encrypting and decrypting a message.

Why RSA Encryption?

RSA encryption provides a robust method of securing data by leveraging a pair of keys — a public key for encryption and a private key for decryption. This asymmetric encryption ensures that only the intended recipient, who possesses the private key, can decrypt the encrypted data.

Understanding RSA Encryption and Data Chunk Limitation

RSA (Rivest–Shamir–Adleman) is an asymmetric encryption algorithm widely used for secure data transmission. It uses a pair of keys—a public key for encryption and a private key for decryption.

ECB (Electronic Codebook) is a mode of operation for block ciphers where each block of plaintext is encrypted independently.

PKCS1Padding is a padding scheme used with RSA to ensure that plaintext is the correct length for encryption.

RSA encryption has a limitation on the size of data it can encrypt in a single operation. For a 2048-bit RSA key, the maximum size of data that can be encrypted is 245 bytes, after accounting for padding (11 bytes for PKCS1Padding). If the data exceeds this limit, it must be split into chunks, encrypted individually, and then combined.

Overcoming the 245-Byte Limitation

To handle data larger than 245 bytes, we need to split the data into smaller chunks that fit within the RSA encryption limit, encrypt each chunk separately, and then concatenate the encrypted chunks. This process ensures that all data is securely encrypted without exceeding the algorithm's limitations.

Storing Public and Private Keys in Cloud Integration Secure Parameters

Before diving into the encryption and decryption process, it’s crucial to store your public and private keys securely within Cloud Integration. These keys are essential for the encryption and decryption operations, and storing them securely ensures that they are only accessible by authorized processes.

2024-08-28_11-27-00.png

Steps to Store the Keys:

  1. Generate the Keys: First, generate your RSA key pair [2048-bit RSA key]. The public key should be in X.509 format, and the private key should be in PKCS8 format.

  2. Access the Secure Store in Cloud Integration:

    • Log in to your SAP Cloud Integration tenant.
    • Navigate to the Operations View.
  3. Create Secure Parameters:

    • Go to Manage Security > Secure Parameters.
    • Click on Add to create a new secure parameter.
    • Name the parameter appropriately (e.g., RSA_PublicKey_X.509 for the public key and RSA_PrivateKey_PKCS8 for the private key).
    • Paste your PEM-encoded keys into the value field.
      • Note: Before pasting the PEM-encoded keys, ensure that you remove the -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY----- (or -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----) lines. Also, remove any new line characters, so the key content is in a single continuous line. This is essential for the key to be properly processed in the Cloud Integration environment.
    • Save the parameters.

    This ensures that your RSA keys are stored securely and can be accessed within your Groovy scripts.

Integration Process Steps in SAP Cloud Integration

Now that your keys are securely stored, let’s walk through the integration process steps used to encrypt and decrypt data within SAP Cloud Integration:

  1. Content Modifier: This sets up the initial sample XML data that will be used for encryption. This data is in its unencrypted form.

  2. Groovy Script (EncryptData): The encryptData function is called. This function handles the encryption of the message. The original message is split into chunks if necessary, each chunk is encrypted using RSA, and the encrypted data is encoded in Base64 to ensure safe transmission. The output is an RSA-encrypted message encoded in Base64.

  3. Base64 Decoder: This step decodes the RSA-encrypted data from Base64 back into its binary form. This step is crucial if we need to process the encrypted binary data directly.

  4. Base64 Encoder: After processing the binary data, this step re-encodes it into Base64 format, making it easier to handle and transmit.

  5. Groovy Script (DecryptData): The decryptData function is called. This function handles the decryption of the encrypted message. It reverses the process, decoding the Base64 data, decrypting it in chunks, and reassembling the original message.

2024-08-28_11-30-55.png

Stimulating Integration Flow

  1. Plain Text2024-08-28_11-35-06.png
  2. Encrypted Data - Base 64 Encoded2024-08-28_11-35-27.png
  3. Encrypted Data - Binary2024-08-28_12-26-54.png
  4. Decrypted Data2024-08-28_11-36-00.png

Groovy Script Breakdown

Here’s a simplified explanation of the Groovy script used for encryption and decryption:

  • decryptData Function:

    • The function starts by retrieving the encrypted data from the message body.
    • It accesses the private key, which is stored securely using the SecureStoreService in Cloud Integration. This key is in PKCS8 format.
    • The decryptDataInChunks method is used to decrypt the data in chunks (256 bytes each, considering the 2048-bit RSA key).
    • The decrypted data is then set back to the message body.
  • encryptData Function:

    • This function retrieves the unencrypted data from the message body.
    • It accesses the public key, which is stored securely in Cloud Integration. This key is in X.509 format.
    • The encryptDataInChunks method encrypts the data in 245-byte chunks, handling the RSA encryption limit.
    • The encrypted data is then encoded in Base64 and set back to the message body.
  • Helper Functions:

    • getPublicKeyFromPEM and getPrivateKeyFromPEM convert PEM-encoded strings into PublicKey and PrivateKey objects, respectively.
    • decryptDataInChunks decrypts the data in chunks to handle data sizes larger than the RSA limit.
    • encryptDataInChunks performs the encryption in chunks, ensuring that each chunk is within the permissible size for RSA encryption.

Groovy Script

Here’s the full Groovy script for reference:

 

 

import com.sap.gateway.ip.core.customdev.util.Message;
import com.sap.it.api.securestore.SecureStoreService
import com.sap.it.api.securestore.UserCredential
import com.sap.it.api.securestore.exception.SecureStoreException
import com.sap.it.api.ITApiFactory
import javax.crypto.Cipher
import java.security.KeyFactory
import java.security.PrivateKey
import java.security.PublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import java.util.Base64

def Message decryptData(Message message) {
    def encryptedData = message.getBody(String);
    encryptedData = encryptedData.replaceAll("\r\n", '')
    SecureStoreService secureStoreService = ITApiFactory.getService(SecureStoreService.class, null)
    UserCredential userCredential = secureStoreService.getUserCredential("RSA_PrivateKey_PKCS8")
    String privateKeyPEM = userCredential.getPassword().toString()
    message.setBody(decryptDataInChunks(encryptedData, getPrivateKeyFromPEM(privateKeyPEM)))
    return message
}

def Message encryptData(Message message) {
    def decryptedData = message.getBody(String);
    SecureStoreService secureStoreService = ITApiFactory.getService(SecureStoreService.class, null)
    UserCredential userCredential = secureStoreService.getUserCredential("RSA_PublicKey_X.509")
    String publicKeyPEM = userCredential.getPassword().toString()
    message.setBody(encryptDataInChunks(decryptedData, getPublicKeyFromPEM(publicKeyPEM)))
    return message
}

// Convert PEM string to PublicKey object
PublicKey getPublicKeyFromPEM(String key) {
    byte[] encoded = Base64.decoder.decode(key)
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded)
    KeyFactory keyFactory = KeyFactory.getInstance("RSA")
    return keyFactory.generatePublic(keySpec)
}

// Convert PEM string to PrivateKey object
PrivateKey getPrivateKeyFromPEM(String key) {
    byte[] encoded = Base64.decoder.decode(key)
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded)
    KeyFactory keyFactory = KeyFactory.getInstance("RSA")
    return keyFactory.generatePrivate(keySpec)
}

// Decrypt data in chunks
String decryptDataInChunks(String encryptedData, PrivateKey privateKey) {
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
    cipher.init(Cipher.DECRYPT_MODE, privateKey)
    byte[] encryptedBytes = Base64.decoder.decode(encryptedData)
    int chunkSize = 256 // RSA encrypted block size for a 2048-bit key
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream()

    for (int i = 0; i < encryptedBytes.length; i += chunkSize) {
        int chunkLength = Math.min(chunkSize, encryptedBytes.length - i)
        byte[] chunk = cipher.doFinal(encryptedBytes, i, chunkLength)
        outputStream.write(chunk)
    }
    return new String(outputStream.toByteArray())
}

// Encrypt data in chunks
String encryptDataInChunks(String data, PublicKey publicKey) {
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
    cipher.init(Cipher.ENCRYPT_MODE, publicKey)
    int chunkSize = 245 // Maximum chunk size for RSA encryption
    byte[] dataBytes = data.bytes
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream()

    for (int i = 0; i < dataBytes.length; i += chunkSize) {
        int chunkLength = Math.min(chunkSize, dataBytes.length - i)
        byte[] chunk = cipher.doFinal(dataBytes, i, chunkLength)
        outputStream.write(chunk)
    }

    return Base64.encoder.encodeToString(outputStream.toByteArray())
}

 

 

Conclusion

By following this guide, you should be able to implement RSA encryption and decryption in SAP Cloud Integration, overcoming the RSA/ECB/PKCS1Padding limitation for data chunks larger than 245 bytes. The Groovy scripts provided offer a practical approach to handling secure data transmission, ensuring that even large messages are encrypted and decrypted efficiently.

Remember, in this implementation, the public key used is in X.509 format, and the private key is in PKCS8 format. Both keys are securely stored in Cloud Integration's secure parameters. Feel free to adapt this script to your specific requirements, and happy coding!

1 Comment
Labels in this area