Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
gdey_geminius
Contributor

  1. This blog post is intended to give an overall idea on file encryption and decryption process using a key in ABAP. By end of this blog post, we will be able to learn 'how to encrypt a text file or data using a key and in the end we will also able know "how to decrypt the encrypted data using the same key".


You can also try this blog post if you are getting run time error "CX_SEC_SXML_ENCRYPT_ERROR" in class "CL_SEC_SXML_WRITER" during decryption of the data.

Requirement:

Recently I came across a requirement where we have to encrypt the generated file while placing it in application server( t-code - AL11 ). The third party middle-ware reads the file from SAP application server and sends it to the target system. To avoid the misutilization of any sensitive data by the third party middle-ware, we have encoded the file using a key(key is generated every-time, hence the key is unique always) and the key has been shared with the concerned person of the target system via e-mail. I thought to share this so that it can be helpful to someone.

The mechanism mentioned above is called "Symmetric Key Encryption" in Cryptography(as the same key is used in the encryption and decryption process, hence the name "Symmetric").

We will be using the class "CL_SEC_SXML_WRITER" for encryption and decryption process. The class "CL_SEC_SXML_WRITER" contains 3 algorithm for encryption and decryption. Below are the details.

  • AES Algorithm 128 Bit

  • AES Algorithm 192 Bit

  • AES Algorithm 256 Bit


These are the algorithms been followed universally, so even if the target system is a non-SAP system, the encrypted file from SAP can be decrypted using the correct key in the target system and vice-versa(and yes, the algorithm used during encryption process should be used during decryption process, of course).

So, let's demonstrate the complete process of encryption and decryption using a key in ABAP. We will be creating 2 different program. Below are the details.

  • Program 1: We will create a program with name "ZFILE_ENCRYPTION". In this program we will do the following task:-

    • Creation of the file which needs to be encrypted

    • Generation of the "KEY" which will be used in encryption process

    • Encrypting the file with the generated key

    • Sharing the key with intended person via e-mail





  • Program 2: We will create another program with name "ZFILE_DECRYPTION" for decrypting  the encrypted file using the generated key. For the scenario that I have worked on(mentioned above) , this program was not required by me as the decryption has been done in the target system. However, this program can be useful if you are in the receiving end of the encoded file. For demonstration purpose, I will be explaining it in this blog post.The program will do the following task:-

    • Reading the encoded file from application server(t-code : AL11)

    • Decrypting the encode file using the key been received on email

    • Downloading the decrypted file(in readable format)




Let's walks through the both program one after one in details.

Program 1: ZFILE_ENCRYPTION - Encrypting the file using a key

Note: Complete source code has been provided in the end of this blog post.

Step 1: Preparing the text file which needs to be encrypted

This step is pretty straight forward. For demonstration purpose, I will be uploading a text file from presentation server. Below is the sample code for file upload. The data object "LV_DATA" contains the desire data which needs to be encrypted.

You can also generate the file string programmatically instead of uploading it from presentation server.
    DATA:
lt_data TYPE string_t,
lv_data TYPE string,
lv_str TYPE string.
CALL METHOD cl_gui_frontend_services=>gui_upload
EXPORTING
filename = p_path
filetype = 'ASC'
CHANGING
data_tab = lt_data
EXCEPTIONS
file_open_error = 1
file_read_error = 2
no_batch = 3
gui_refuse_filetransfer = 4
invalid_type = 5
no_authority = 6
unknown_error = 7
bad_data_format = 8
header_not_allowed = 9
separator_not_allowed = 10
header_too_long = 11
unknown_dp_error = 12
access_denied = 13
dp_out_of_memory = 14
disk_full = 15
dp_timeout = 16
not_supported_by_gui = 17
error_no_gui = 18
OTHERS = 19.
LOOP AT lt_data INTO lv_str.
IF lv_data IS INITIAL.
lv_data = lv_str.
ELSE.
lv_data = |{ lv_data }{ cl_abap_char_utilities=>newline }{ lv_str }|.
ENDIF.
ENDLOOP.

Source file is looking like this:



Step 2: Generating the key for encryption

We have to generate the "KEY" which will be used in encryption process. "GENERATE_KEY" method of the class "CL_SEC_SXML_WRITER" can be used for that. The method always returns a unique "XSTRING" every-time.
DATA:
lv_key TYPE xstring.

lv_key = cl_sec_sxml_writer=>generate_key( algorithm = cl_sec_sxml_writer=>co_aes128_algorithm ).

Important: Please do not use the class "CL_ABAP_CONV_OUT_CE" for generation of the "KEY" for encryption. If you do so, you the program will dump if the encryption and decryption program are different. Below is the screenshot of the dump.



Step 3: Encrypting the file using the key

Till now we have prepared the data which needs to be encrypted and the key is also generated which will be used for encryption. For that we have to use the method "ENCRYPT" of class "CL_SEC_SXML_WRITER". The arguments of the method is the key which been derived in the above step, the data(which needs to be encrypted) in "XSTRING" format and the name of the algorithm which needs to be used. Below is the sample code
DATA:
lv_data_xstr TYPE xstring,
lv_msg TYPE xstring.

"Converting the data - From string format to xstring. You can use any other method or function module which converts the string to xstring format
lv_data_xstr = cl_bcs_convert=>string_to_xstring(
iv_string = lv_data " Input data
).

"Encrypt the data using the key
cl_sec_sxml_writer=>encrypt(
EXPORTING
plaintext = v_data
key = v_key
algorithm = cl_sec_sxml_writer=>co_aes128_algorithm
IMPORTING
ciphertext = lv_msg ).

Step 4: Saving the encrypted file in application server

Now that we have encrypted the file, we have to save the encrypted file in application server(t-code: AL11). But, please note the encrypted file in "XSTRING" format. So, how to transfer the "XSTRING" to application sever. Yes, you are right, just assign the "XSTRING" to a "STRING" data object and transfer the string to the application server. As simple as that. Below is the code snipet.
DATA:
lv_str TYPE string.

CONSTANTS:
lc_filepath TYPE string VALUE '\\PGRDEV\sapmnt\trans\file_after_encryption.txt"

lv_str = lv_msg.

"Split at 132 position
CALL FUNCTION 'CONVERT_STRING_TO_TABLE'
EXPORTING
i_string = lv_str
i_tabline_length = 132
TABLES
et_table = lt_str.

OPEN DATASET lc_filepath IN TEXT MODE FOR OUTPUT ENCODING DEFAULT.

"Loop at all the line
LOOP AT lt_str INTO lv_str.
TRANSFER lv_str TO lc_filepath.
ENDLOOP.

CLOSE DATASET lc_filepath.

Encrypted file in AL11 looks like below. Now the data is been encrypted using the key.



Step 5: Sending generated key with concerned person via email.

There are many blog post and thread available for explaining how to send email in ABAP. So, I am not covering that in this blog post. However, you can find the code in the bottom section of this blog post.

Program 2: ZFILE_DECRYPTION : Decrypting the file using the generated key

Note: Complete source code has been provided in the end of this blog post.

Step 1: Reading the encrypted file from application server

We are reading the encrypted file from application server(t-code: AL11) using "OPEN DATASET". Please refer to below link if you are new to this.

https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abapopen_dataset.htm
DATA:
lv_str TYPE string,
lv_data TYPE string.

CONSTANTS:
lc_filepath TYPE string VALUE '\\PGRDEV\sapmnt\trans\file_after_encryption.txt'.

OPEN DATASET lc_filepath FOR INPUT IN TEXT MODE ENCODING DEFAULT.

DO.
READ DATASET lc_filepath INTO lv_str.
IF sy-subrc NE 0.
EXIT.
ENDIF.
lv_data = |{ lv_data }{ lv_str }|.
ENDDO.

 

Step 2: Decrypting the file using the key

Now that we have read the encrypted data from application server(t-code: AL11) and we have the received the generated key(the key is received over email - refer to Step 5 of Program 1 above), we have to decrypt the data using method "DECRYPT" of class "CL_SEC_SXML_WRITER" . The methods has the arguments for "encrypted data", "the key which was used during encryption", "the algorithm which was used during "encryption".

The data object "LV_DATA" has the encrypted data(derived from above step). The data type the data object is "string". We have to assign it to a data object  of type "XSTRING". Then we can decrypt the data. Below source code for reference
    DATA:
lt_binary TYPE STANDARD TABLE OF x255.

DATA:
lv_message_decrypted TYPE xstring,
lv_str TYPE string,
lv_key TYPE xstring,
lv_data_xstr TYPE xstring,
lv_data_text TYPE string,
lv_length TYPE i.

"Received key - As already discussed the key has been shared with the cocern person. The key has been assign here so that we can decrypt the file
lv_key = '38451B52187A3A4AECA26B27AE79D147'

"Assign the encrypted data derived in previous step to to xstring data object so that the same can be decrypted
lv_data_xstr = lv_data.

"Decrypt message
cl_sec_sxml_writer=>decrypt(
EXPORTING
ciphertext = lv_data_xtr
key = lv_key
algorithm = cl_sec_sxml_writer=>co_aes128_algorithm
IMPORTING
plaintext = lv_message_decrypted ).

"LV_MESSAGE_DECRYPTED data object now contains the decrypted data in xstring format. So, to make as human readable, we have to convert the xstring to string.

"Convert xstring to binary
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
buffer = lv_message_decrypted
IMPORTING
output_length = lv_length
TABLES
binary_tab = lt_binary.

"Binary to string
CALL FUNCTION 'SCMS_BINARY_TO_STRING'
EXPORTING
input_length = lv_length
IMPORTING
text_buffer = lv_data_text
TABLES
binary_tab = lt_binary
EXCEPTIONS
failed = 1
OTHERS = 2.

Now that you have got the decrypted data, you can process it or can download to presentation server as per the requirement. I have download the file to the presentation server for demonstration. Please refer to attached source code file for details.

Decrypted file looks like below


Conclusion:


So, in this blog post we are able to encrypt the data/text file using a key(the key was generated during run-time). The key has been shared with the concerned person over e-mail. A separate decryption program has been created which decrypts the data using the key been shared.

Hope this blog post will help someone.

Complete source code has been given below for both the program - encryption and decryption

Prorgram: ZFILE_ENCRYPTION


*&---------------------------------------------------------------------*
*& Report ZFILE_ENCRYPTION
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

REPORT zfile_encryption.

PARAMETERS:
p_path TYPE string OBLIGATORY LOWER CASE.

*----------------------------------------------------------------------*
* CLASS lcl_encryption DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_encryption DEFINITION.

PUBLIC SECTION.

CLASS-METHODS:
select_file,
upload_file
RAISING cx_bcs,
encrypt_file,
send_email.

CONSTANTS:
c_filepath TYPE string VALUE '\\PGRDEV\sapmnt\trans\encrypted_file.txt'.

PRIVATE SECTION.

CLASS-DATA:
v_data TYPE xstring,
v_key TYPE xstring.

ENDCLASS. "lcl_encryption DEFINITION

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_path.

"Select file
lcl_encryption=>select_file( ).

START-OF-SELECTION.

"Upload file
lcl_encryption=>upload_file( ).

"Encrypted file
lcl_encryption=>encrypt_file( ).

*----------------------------------------------------------------------*
* CLASS lcl_test IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_encryption IMPLEMENTATION.

METHOD select_file.

DATA:
lt_file TYPE filetable,
ls_file TYPE file_table,
lv_rc TYPE i.

CALL METHOD cl_gui_frontend_services=>file_open_dialog
CHANGING
file_table = lt_file
rc = lv_rc
EXCEPTIONS
file_open_dialog_failed = 1
cntl_error = 2
error_no_gui = 3
not_supported_by_gui = 4
OTHERS = 5.

IF sy-subrc EQ 0.

READ TABLE lt_file INTO ls_file INDEX 1.

IF sy-subrc EQ 0.
p_path = ls_file.
ENDIF.

ENDIF.

ENDMETHOD. "upload_file

METHOD upload_file.

DATA:
lt_data TYPE string_t,
lv_data TYPE string,
lv_str TYPE string.

CLEAR v_data.

CALL METHOD cl_gui_frontend_services=>gui_upload
EXPORTING
filename = p_path
filetype = 'ASC'
CHANGING
data_tab = lt_data
EXCEPTIONS
file_open_error = 1
file_read_error = 2
no_batch = 3
gui_refuse_filetransfer = 4
invalid_type = 5
no_authority = 6
unknown_error = 7
bad_data_format = 8
header_not_allowed = 9
separator_not_allowed = 10
header_too_long = 11
unknown_dp_error = 12
access_denied = 13
dp_out_of_memory = 14
disk_full = 15
dp_timeout = 16
not_supported_by_gui = 17
error_no_gui = 18
OTHERS = 19.

LOOP AT lt_data INTO lv_str.

IF lv_data IS INITIAL.
lv_data = lv_str.
ELSE.
lv_data = |{ lv_data }{ cl_abap_char_utilities=>newline }{ lv_str }|.
ENDIF.

ENDLOOP.

"Convert to xstring
v_data = cl_bcs_convert=>string_to_xstring(
iv_string = lv_data " Input data
).

ENDMETHOD. "upload_file

METHOD encrypt_file.

DATA:
lt_str TYPE string_t,
lv_str TYPE string,
lv_msg TYPE xstring.

v_key = cl_sec_sxml_writer=>generate_key( algorithm = cl_sec_sxml_writer=>co_aes128_algorithm ).

"encrypt using AES256
cl_sec_sxml_writer=>encrypt(
EXPORTING
plaintext = v_data
key = v_key
algorithm = cl_sec_sxml_writer=>co_aes128_algorithm
IMPORTING
ciphertext = lv_msg ).

lv_str = lv_msg.

"Split at 132 position
CALL FUNCTION 'CONVERT_STRING_TO_TABLE'
EXPORTING
i_string = lv_str
i_tabline_length = 132
TABLES
et_table = lt_str.

OPEN DATASET c_filepath IN TEXT MODE FOR OUTPUT ENCODING DEFAULT.

"Loop at all the line
LOOP AT lt_str INTO lv_str.
TRANSFER lv_str TO c_filepath.
ENDLOOP.

CLOSE DATASET c_filepath.

"Send email
send_email( ).

MESSAGE 'File saved in AL11' TYPE 'I'.

ENDMETHOD. "encrypt_file

METHOD send_email.

CONSTANTS:
lc_subject TYPE so_obj_des VALUE 'Encryption key',
lc_raw TYPE char03 VALUE 'RAW'.

DATA:
lr_send_request TYPE REF TO cl_bcs,
lr_bcs_exception TYPE REF TO cx_bcs,
lr_recipient TYPE REF TO if_recipient_bcs,
lr_sender TYPE REF TO cl_sapuser_bcs,
lr_document TYPE REF TO cl_document_bcs.

DATA:
lv_mlrec TYPE so_obj_nam,
lv_sent_to_all TYPE os_boolean,
lv_email TYPE adr6-smtp_addr,
lv_subject TYPE so_obj_des,
lv_str TYPE string,
lv_text TYPE bcsy_text.

TRY.

"Create send request
lr_send_request = cl_bcs=>create_persistent( ).

"Email FROM...
lr_sender = cl_sapuser_bcs=>create( sy-uname ).

"Add sender to send request
CALL METHOD lr_send_request->set_sender
EXPORTING
i_sender = lr_sender.

"Email TO...
lv_email = 'testing@testing.com'.

lr_recipient = cl_cam_address_bcs=>create_internet_address( lv_email ).

"Add recipient to send request
CALL METHOD lr_send_request->add_recipient
EXPORTING
i_recipient = lr_recipient
i_express = 'X'.

"Email BODY
lv_str = |Encryption key :{ v_key }|.

APPEND lv_str TO lv_text.

lr_document = cl_document_bcs=>create_document(
i_type = lc_raw
i_text = lv_text
i_length = '12'
i_subject = lc_subject ).

"Add document to send request
CALL METHOD lr_send_request->set_document( lr_document ).

"Send email
CALL METHOD lr_send_request->send(
EXPORTING
i_with_error_screen = 'X'
RECEIVING
result = lv_sent_to_all ).

IF lv_sent_to_all = 'X'.
WRITE 'Email sent!'.
ENDIF.

"Commit to send email
COMMIT WORK.

"Exception handling
CATCH cx_bcs INTO lr_bcs_exception.

WRITE:
'Error!',
'Error type:',
lr_bcs_exception->error_type.

ENDTRY.

ENDMETHOD. "send_email

ENDCLASS. "lcl_test IMPLEMENTATION

Prorgram: ZFILE_DECRYPTION


*&---------------------------------------------------------------------*
*& Report ZFILE_ENCRYPTION
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

REPORT zfile_decryption.

PARAMETERS:
p_key TYPE string OBLIGATORY LOWER CASE.

*----------------------------------------------------------------------*
* CLASS lcl_encryption DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_decryption DEFINITION.

PUBLIC SECTION.

CLASS-METHODS:
read_file,
decrypt_file,
download_file.

CONSTANTS:
c_filepath TYPE string VALUE '\\PGRDEV\sapmnt\trans\encrypted_file.txt'.

PRIVATE SECTION.

CLASS-DATA:
v_data TYPE xstring,
v_data_text TYPE string,
v_key TYPE xstring.

ENDCLASS. "lcl_encryption DEFINITION

START-OF-SELECTION.

"Upload file
lcl_decryption=>read_file( ).

"Decryptfile
lcl_decryption=>decrypt_file( ).

"Download file
lcl_decryption=>download_file( ).

*----------------------------------------------------------------------*
* CLASS lcl_test IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_decryption IMPLEMENTATION.

METHOD read_file.

DATA:
lv_str TYPE string,
lv_data TYPE string.

v_key = p_key.

OPEN DATASET c_filepath FOR INPUT IN TEXT MODE ENCODING DEFAULT.

DO.

READ DATASET c_filepath INTO lv_str.
IF sy-subrc NE 0.
EXIT.
ENDIF.
lv_data = |{ lv_data }{ lv_str }|.

ENDDO.

v_data = lv_data.

ENDMETHOD. "upload_file

METHOD decrypt_file.

DATA:
lt_binary TYPE STANDARD TABLE OF x255.

DATA:
lv_message_decrypted TYPE xstring,
lv_str TYPE string,
lv_length TYPE i.

"Decrypt message
cl_sec_sxml_writer=>decrypt(
EXPORTING
ciphertext = v_data
key = v_key
algorithm = cl_sec_sxml_writer=>co_aes128_algorithm
IMPORTING
plaintext = lv_message_decrypted ).

"Convert xstring to binary
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
buffer = lv_message_decrypted
IMPORTING
output_length = lv_length
TABLES
binary_tab = lt_binary.

"Binary to string
CALL FUNCTION 'SCMS_BINARY_TO_STRING'
EXPORTING
input_length = lv_length
IMPORTING
text_buffer = v_data_text
TABLES
binary_tab = lt_binary
EXCEPTIONS
failed = 1
OTHERS = 2.

ENDMETHOD. "upload_file

METHOD download_file.

DATA:
lv_filename TYPE string,
lv_path TYPE string,
lv_fullpath TYPE string,
lt_string TYPE string_t.

"File save dialog
CALL METHOD cl_gui_frontend_services=>file_save_dialog
CHANGING
filename = lv_filename
path = lv_path
fullpath = lv_fullpath
EXCEPTIONS
cntl_error = 1
error_no_gui = 2
not_supported_by_gui = 3
invalid_default_file_name = 4
OTHERS = 5.

APPEND v_data_text TO lt_string.

CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
filename = lv_fullpath
filetype = 'ASC'
CHANGING
data_tab = lt_string
EXCEPTIONS
file_write_error = 1
no_batch = 2
gui_refuse_filetransfer = 3
invalid_type = 4
no_authority = 5
unknown_error = 6
header_not_allowed = 7
separator_not_allowed = 8
filesize_not_allowed = 9
header_too_long = 10
dp_error_create = 11
dp_error_send = 12
dp_error_write = 13
unknown_dp_error = 14
access_denied = 15
dp_out_of_memory = 16
disk_full = 17
dp_timeout = 18
file_not_found = 19
dataprovider_exception = 20
control_flush_error = 21
not_supported_by_gui = 22
error_no_gui = 23
OTHERS = 24.

ENDMETHOD. "download_file

ENDCLASS. "lcl_test IMPLEMENTATION
19 Comments