Skip to Content
Technical Articles

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.

Sources:

https://advantco.com/product/solution/pgp

 

Be the first to leave a comment
You must be Logged on to comment or reply to a post.