Using PGP encryption in ABAP program
1. Introduction
There many use cases where one wants to have the data encrypted before it is written to a file or send to an external application or integration platform. This blog describes one solution by using the Advantco PGP Webservice to encrypt/decrypt data in SAP ECC or SAP S/4HANA.
2.Architecture
The Advantco PGP Webservice (PGP WS) is an application that runs on any SAP JAVA Netweaver. The PGP WS exposes different SOAP services that handle the data encryption/decryption using PGP.
3.Advantco PGP Webservice components
PGP Keymanager manages the PGP keys that are used by the PGP WS. This tool can generate new private key pairs, export public key for partners or import partner’s public key.
PGP Webservices is the core of the solution, it provides the SOAP services to enable encryption/decryption and signing/verification of signatures.
4. High level configuration and implementation steps.
Step 1: Goto Transaction Code [SE80] and create the webservice through Enterprise service option as below.
Choose the Service Consumer->WSDL->URL option and pass the URL ( https://netweaver_host:port/AdvantcoOpenPGPSendingService/OpenPGPSendingService?wsdl&mode=ws_policy )
of Webservice OpenPGPSendingService
Save the service in Package->transport request and give the prefix to generate the Service Consumer as like below.
Step 2: Go to Transaction code SOAMANAGER and choose the option “Web Service Configuration”
Select the Consumer service from search option by name and click on the service.
It will open the below screen to define the Logical Port.
Choose the WSDL based configuration option for creation of Port.
Define Logical port will followed with wizard( step by step ) option. Pass the values and create the Port for SAP Server/Client in which Service Consumer has been created and activated. Save the Port as Logical Port Name ‘PGPSENDERPORT’
Once Port has been created for specific Service Consumer-> WebService-> URL Check the Webservice thorogh “Ping Web Service” Button.
Step 3: When Service Consumer has been activated; System generate the Class and methods to call the webservice through SAP server by passing the Key, PhraseKey and Logicalport name. Data can be sent through encrypt and encrypt_text methods.
As an example of sending the vendor Invoice data, followed the below steps. The ABAP code below is just for sample purpose, it should be handle accordingly.
a) For MIGO transaction code -> Implemented the BADI INVOICE_UPDATE through transaction code SE18 -> Created the enhancement and BADI implementation class (ZCL_IM_PGP_SEND_INV_DETAIL) and implemented the methods of class.
b) Written the logic to the method -> IF_EX_INVOICE_UPDATE~CHANGE_BEFORE_UPDATE
c) Created new Function module (ZPGP_SEND_VENDOR_INV_DETAIL) to populate the data in local structure/table which will be passed in the encrypt_text method of class (ZPGPCO_OPEN_PGPSENDING_SERVICE) .
d) Once Parameter table( ZPGP_PARAM_VALUE) has been created to save the Key, passPharas and LogicalPort name for specific user.
Decrypted the Key, Passphras and Lock Object values from ZPGP_PARAM_VALUE table and pass to method (encrypt_text) exporting parameter Input_text.
Once data has been sent to external webservice; It return the value in Binary mode(base64).
e) Convert the base64 data from im_output_text-encrypt_text_response-return.
Pass the value im_output_text-encrypt_text_response-return to XSTRING local available to LV_XSTR.
Converted the XSTRING to String by using the FM ‘SCMS_BASE64_ENCODE_STR’ and saved the data on application server file by using the Open dataset, Transfer and Close Dataset option.
function zpgp_send_vendor_inv_details.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" VALUE(ST_RBKP_NEW) TYPE RBKP
*" EXPORTING
*" VALUE(ET_VEN_INV) TYPE ZPGP_TT_VENDOR_INVOICE_DETAILS
*" TABLES
*" TT_MRMRSEG STRUCTURE MRMRSEG OPTIONAL
*" TT_MRMRBCO STRUCTURE MRMRBCO OPTIONAL
*" TT_MRMRBMA STRUCTURE MRMRBMA OPTIONAL
*" TT_MRMRBTX STRUCTURE MRMRBTX OPTIONAL
*" TT_MRMRBVS STRUCTURE MRMRBVS OPTIONAL
*" TT_MRMRBWS STRUCTURE MRMRBWS OPTIONAL
*"----------------------------------------------------------------------
*> This FM has been called from BADI INVOICE_UPDATE-> Implementation ZPGP_SEND_INV_DETAIL
*> It sends the data to PGP through webservice when Transaction MIGO create the Vendor
*> Invoice document.
data: lo_senderpgp type ref to zpgpco_open_pgpsending_service,
ex_input_text type zpgpencrypt_text_in,
im_output_text type zpgpencrypt_text_out,
lt_ven_inv type zpgp_tt_vendor_invoice_details,
ls_ven_inv type zpgp_st_vendor_invoice_details,
lv_str type string,
lv_xstr type xstring,
ls_str type string,
lv_encoded_str type string,
lv_decoded_str type string,
lt_str type table of string.
data : lv_tabname type dntab-tabname value 'ZPGP_ST_VENDOR_INVOICE_DETAILS',
lv_wrbtr type char20,
lv_menge type char20,
ls_header type dntab,
lt_header type standard table of dntab.
data: lo_sfault type ref to cx_ai_system_fault,
lo_jfault type ref to zpgpcx_encrypt_fault,
lo_afault type ref to cx_ai_application_fault.
select single * from zpgp_param_value into @data(ls_param_value)
where object_type = 'CLAS' and
object_name = 'ZPGP_SEND_INV_DETAIL' and
field_name = 'USER_INVOICE_KEY' and
from_value = @sy-uname.
check ls_param_value-text1 is not initial.
*"----------------------------------------------------------------------
clear : lv_encoded_str, lv_decoded_str.
lv_encoded_str = ls_param_value-text1.
clear ls_param_value-text1.
call method cl_http_utility=>if_http_utility~decode_base64 "Method for Decryption
exporting
encoded = lv_encoded_str
receiving
decoded = lv_decoded_str.
call method cl_http_utility=>if_http_utility~decode_base64 "Method for Decryption
exporting
encoded = lv_decoded_str
receiving
decoded = lv_decoded_str.
ls_param_value-text1 = lv_decoded_str.
ex_input_text-parameters-encryption_key_id = ls_param_value-text1. " 'pgpkeyhere' .
*"----------------------------------------------------------------------
clear : lv_encoded_str, lv_decoded_str.
lv_encoded_str = ls_param_value-text2.
clear ls_param_value-text2.
call method cl_http_utility=>if_http_utility~decode_base64 "Method for Decryption
exporting
encoded = lv_encoded_str
receiving
decoded = lv_decoded_str.
call method cl_http_utility=>if_http_utility~decode_base64 "Method for Decryption
exporting
encoded = lv_decoded_str
receiving
decoded = lv_decoded_str.
ls_param_value-text2 = lv_decoded_str.
ex_input_text-parameters-encryption_symmetric_passphras = ls_param_value-text2.
"'passwordhere' ."'0x594A9EB3'.
*"----------------------------------------------------------------------
call function 'NAMETAB_GET'
exporting
tabname = lv_tabname
tables
nametab = lt_header.
data(lv_no_of_columns) = lines( lt_header ).
loop at lt_header into ls_header.
if ls_str is initial.
ls_str = ls_header-fieldtext.
continue.
endif.
ls_str = | { ls_str } ; { ls_header-fieldtext } |.
endloop.
append ls_str to lt_str.
read table tt_mrmrseg into data(ls_mrmrseg) index 1.
move-corresponding ls_mrmrseg to ls_ven_inv.
loop at tt_mrmrbco into data(ls_mrmrbco).
move-corresponding ls_mrmrbco to ls_ven_inv.
lv_wrbtr = ls_ven_inv-wrbtr.
lv_menge = ls_ven_inv-menge.
concatenate ls_ven_inv-belnr
ls_ven_inv-gjahr
ls_ven_inv-bukrs
ls_ven_inv-blart
ls_ven_inv-buzei
lv_wrbtr
ls_ven_inv-werks
ls_ven_inv-saknr
ls_ven_inv-kokrs
ls_ven_inv-txjcd
ls_ven_inv-ebeln
ls_ven_inv-ebelp
ls_ven_inv-matnr
lv_menge
ls_ven_inv-lfbnr
into ls_str separated by ';'.
append ls_str to lt_str.
endloop.
clear ls_str.
concatenate lines of lt_str into lv_str separated by cl_abap_char_utilities=>cr_lf.
ex_input_text-parameters-input_data = lv_str.
try.
clear : lv_encoded_str, lv_decoded_str.
lv_encoded_str = ls_param_value-text3.
clear ls_param_value-text3.
call method cl_http_utility=>if_http_utility~decode_base64 "Method for Decryption
exporting
encoded = lv_encoded_str
receiving
decoded = lv_decoded_str.
call method cl_http_utility=>if_http_utility~decode_base64 "Method for Decryption
exporting
encoded = lv_decoded_str
receiving
decoded = lv_decoded_str.
ls_param_value-text3 = lv_decoded_str.
create object lo_senderpgp exporting logical_port_name = ls_param_value-text3 .
"'PGPSENDERPORT'.
catch cx_ai_system_fault .
endtry.
* call the ws try.
try.
call method lo_senderpgp->encrypt_text
exporting
input = ex_input_text
importing
output = im_output_text.
catch cx_ai_system_fault into lo_sfault.
exit.
catch zpgpcx_encrypt_fault into lo_jfault.
exit.
catch cx_ai_application_fault into lo_afault.
exit.
endtry.
select single * from zpgp_param_value into @data(ls_file_path)
where object_type = 'CLAS' and
object_name = 'ZPGP_SEND_INV_DETAIL' and
field_name = 'FILE_PATH' and
from_value = @sy-uname.
*>> write the binary xstring to a file open dataset dsn for output in text mode.
check ls_file_path-text1 is not initial and im_output_text-encrypt_text_response-return
is not initial.
clear : lv_xstr, lv_str.
move im_output_text-encrypt_text_response-return to lv_xstr.
call function 'SCMS_BASE64_ENCODE_STR'
exporting
input = lv_xstr
importing
output = lv_str.
concatenate ls_file_path-text1 ls_mrmrseg-belnr '_' sy-datum sy-uzeit '.txt'
into ls_file_path-text1.
condense ls_file_path-text1 no-gaps.
open dataset ls_file_path-text1 in text mode for output encoding default.
if sy-subrc ne 0.
exit.
endif.
transfer lv_str to ls_file_path-text1.
close dataset ls_file_path-text1.
clear : lv_xstr, lv_str.
endfunction.
f) Uploaded data will be available on application server [ AL11 ] as txt file like below
5. Conclusion
Data can be encrypted before leaving the SAP back-end systems. The Advantco PGP Webservice provides a powerful solution that includes a PGP Keymanager and set of PGP services.
Please reach out to our sales team at sales@advantco.com if you have any questions.