BankgiroCentralen BGC HMAC SAP ABAP
License
This code is currently in beta.
Give it a testspin.
Idea for usage.
Store the key in a file at a USB stick with encryption.
Store the key at yet another USB stick with encryption as a backup.
Attach the USB stick to the pc.
Makue sure the files to be sent to the bank can be accessed from the pc being used to execute the sap gui.
Typically the files to be sent to the bank are written to the file system of the SAP server.
There are a number of options to access the files:
- ftp/sftp client to download the files from the SAP server.
- Access the files using common internet file system (CIFS)
- expose the fileshare at SAP server using samba if on unix or as a windows file share.
- let the sap server write the files to a windows file share (if on linux a file system mounted as cifs)
- use zapcmd, a norton comander clone for SAP to download the files
- use transaction CG3Y to download the file
Use the ZBGC_HMAC report to tamper protect (seal) the files.
Veryfy that the files are correct after adding the seal but before sending the files to the bank.
A VPN to the bank should be established, to send the files to the bank using a ftp client at the pc.
When done, store the USB sticks in a safe.
If you need an automated solution, consultants can help to customize to the specific requirements.
*&---------------------------------------------------------------------*
*& Report ZBGC_HMAC
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zbgc_hmac.
* Author: Otto Frost @ Nuport
TYPE-POOLS abap.
SELECTION-SCREEN COMMENT /1(50) comm1 MODIF ID mg1.
SELECTION-SCREEN ULINE.
SELECTION-SCREEN SKIP.
PARAMETERS p_inf TYPE file_name lower case.
PARAMETERS p_keyf TYPE file_name lower case.
PARAMETERS p_outf TYPE file_name lower case.
PARAMETERS p_test TYPE c AS CHECKBOX.
DATA i_filetable TYPE filetable.
DATA w_rc TYPE i.
DATA w_pathfd TYPE string.
DATA w_pathd TYPE string.
DATA w_filenamed TYPE string.
AT SELECTION-SCREEN OUTPUT.
comm1 = 'BankGiroCentralen BGC HMAC'.
LOOP AT SCREEN.
IF screen-group1 = 'MG1'.
screen-intensified = '1'.
MODIFY SCREEN.
ENDIF.
ENDLOOP.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_inf.
refresh i_filetable.
CALL METHOD cl_gui_frontend_services=>file_open_dialog
* EXPORTING
* WINDOW_TITLE =
* DEFAULT_EXTENSION =
* DEFAULT_FILENAME =
* FILE_FILTER =
* WITH_ENCODING =
* INITIAL_DIRECTORY =
* MULTISELECTION =
CHANGING
file_table = i_filetable
rc = w_rc
* USER_ACTION =
* FILE_ENCODING =
* EXCEPTIONS
* FILE_OPEN_DIALOG_FAILED = 1
* CNTL_ERROR = 2
* ERROR_NO_GUI = 3
* NOT_SUPPORTED_BY_GUI = 4
* others = 5
.
IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
* WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
READ TABLE i_filetable INDEX 1 INTO p_inf.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_keyf.
refresh i_filetable.
CALL METHOD cl_gui_frontend_services=>file_open_dialog
* EXPORTING
* WINDOW_TITLE =
* DEFAULT_EXTENSION =
* DEFAULT_FILENAME =
* FILE_FILTER =
* WITH_ENCODING =
* INITIAL_DIRECTORY =
* MULTISELECTION =
CHANGING
file_table = i_filetable
rc = w_rc
* USER_ACTION =
* FILE_ENCODING =
* EXCEPTIONS
* FILE_OPEN_DIALOG_FAILED = 1
* CNTL_ERROR = 2
* ERROR_NO_GUI = 3
* NOT_SUPPORTED_BY_GUI = 4
* others = 5
.
IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
* WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
READ TABLE i_filetable INDEX 1 INTO p_keyf.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_outf.
w_pathfd = p_outf.
CALL METHOD cl_gui_frontend_services=>file_save_dialog
* EXPORTING
* WINDOW_TITLE =
* DEFAULT_EXTENSION =
* DEFAULT_FILE_NAME =
* WITH_ENCODING =
* FILE_FILTER =
* INITIAL_DIRECTORY =
* PROMPT_ON_OVERWRITE = 'X'
CHANGING
filename = w_filenamed
path = w_pathd
fullpath = w_pathfd
* USER_ACTION = W_USER_ACTION
* FILE_ENCODING =
* EXCEPTIONS
* CNTL_ERROR = 1
* ERROR_NO_GUI = 2
* NOT_SUPPORTED_BY_GUI = 3
* others = 4
.
IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
* WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
p_outf = w_pathfd.
INITIALIZATION.
START-OF-SELECTION.
IF p_test = abap_true.
PERFORM test.
ELSE.
PERFORM bgc_hmac.
ENDIF.
*----------------------------------------------------------------------*
* CLASS zcl_bgc_hmac DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS zcl_bgc_hmac DEFINITION.
PUBLIC SECTION.
METHODS test.
METHODS createsignature IMPORTING
value(keyfile) TYPE string
value(infile) TYPE string
value(outfile) TYPE string
value(date) TYPE string
value(ls) TYPE string.
PROTECTED SECTION.
* package section.
PRIVATE SECTION.
TYPES t_linex(512) TYPE x.
CONSTANTS co_empty TYPE string VALUE ''.
METHODS normalize IMPORTING value(s) TYPE string RETURNING value(r) TYPE string.
METHODS bgc_hmac IMPORTING value(indata) TYPE string value(keyhex) TYPE string RETURNING value(r) TYPE string.
METHODS sealopeningrecord IMPORTING value(date) TYPE string RETURNING value(r) TYPE string.
METHODS tamperprotectionrecord IMPORTING value(kvv) TYPE string value(mac) TYPE string value(date) TYPE string RETURNING value(r) TYPE string.
METHODS xtab2xstring IMPORTING value(tab) TYPE ANY TABLE value(length) TYPE i RETURNING value(r) TYPE xstring.
ENDCLASS. "zcl_bgc_hmac DEFINITION
*----------------------------------------------------------------------*
* CLASS zcl_bgc_hmac IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS zcl_bgc_hmac IMPLEMENTATION.
METHOD test.
DATA indata TYPE string.
DATA key TYPE string VALUE '1234567890ABCDEF1234567890ABCDEF'.
DATA mac TYPE string.
DATA l_s TYPE string.
DATA l_normalized TYPE string.
DATA l_space TYPE string.
CONCATENATE space space INTO l_space SEPARATED BY space.
indata = 'AAAÅÄÖÜåäöü'.
indata = me->normalize( indata ).
**********
* Test 1A
**********
mac = me->bgc_hmac( indata = '00000000' keyhex = key ).
IF to_upper( mac ) = 'FF365893D899291C3BF505FB3175E880' .
WRITE:/ 'Test 1A ok' .
ELSE .
WRITE:/ 'Test 1A err' .
l_s = to_upper( mac ).
WRITE:/ l_s.
WRITE:/ 'FF365893D899291C3BF505FB3175E880'.
ENDIF.
**********
* Test 1B
**********
indata = '00000' && cl_abap_char_utilities=>cr_lf &&
'0000' && cl_abap_char_utilities=>cr_lf &&
'000' && cl_abap_char_utilities=>cr_lf &&
'00' && cl_abap_char_utilities=>cr_lf && '0' && cl_abap_char_utilities=>cr_lf.
l_normalized = me->normalize( indata ).
* WRITE:/ '1B', space, indata.
* WRITE:/ '1B', space, l_normalized.
mac = me->bgc_hmac( indata = l_normalized keyhex = key ).
IF to_upper( mac ) = '9BA94363739D45256DF4B6FA3B9DE1CD'.
WRITE:/ 'Test 1B ok'.
ELSE.
WRITE:/ 'Test 1B err'.
ENDIF.
**********
* Test 1C
**********
indata =
'110009912346071215LEVERANTZRSBETALNINGAR 2'
&& cl_abap_char_utilities=>cr_lf
&& '10000000C0000000000000000000000000000000000000000000000000000000000000002'
&& cl_abap_char_utilities=>cr_lf
&& '10000000C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002'
&& cl_abap_char_utilities=>cr_lf
&& '10000000C002'
&& cl_abap_char_utilities=>cr_lf.
l_normalized = me->normalize( indata ).
* WRITE:/ '1C', space, indata.
* WRITE:/ '1C', space, l_normalized.
mac = me->bgc_hmac( indata = l_normalized keyhex = key ).
IF to_upper( mac ) = '826CA6CBA33F7E1D3CC9161A0956A35B'.
WRITE:/ 'Test 1C ok'.
ELSE.
WRITE:/ 'Test 1C err'.
ENDIF.
**********
* Test 2A
**********
indata = l_space && '!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~' && cl_abap_char_utilities=>cr_lf.
l_normalized = me->normalize( indata ).
* WRITE:/ '2A', space, indata.
* WRITE:/ '2A', space, l_normalized.
* DATA x TYPE string.
* x = l_space && '!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.
* IF x = l_normalized.
* WRITE:/ '2A normalized ok'.
* ELSE.
* WRITE:/ '2A normalized not ok'.
* ENDIF.
mac = me->bgc_hmac( indata = l_normalized keyhex = key ).
* WRITE:/ mac.
IF to_upper( mac ) = '9473EDFCAA8CD2434D6D76ABFFC991BD'.
WRITE:/ 'Test 2A ok'.
ELSE.
WRITE:/ 'Test 2A err'.
ENDIF.
**********
* Test 2B
**********
indata = 'õÕ^~@`!"#$%&''(' && cl_abap_char_utilities=>horizontal_tab && ')*+,-./§½' && cl_abap_char_utilities=>cr_lf.
l_normalized = me->normalize( indata ).
* WRITE:/ '2B', space, indata.
* WRITE:/ '2B', space, l_normalized.
* DATA x TYPE string.
* x = l_space && '!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.
* IF x = l_normalized.
* WRITE:/ '2A normalized ok'.
* ELSE.
* WRITE:/ '2A normalized not ok'.
* ENDIF.
mac = me->bgc_hmac( indata = l_normalized keyhex = key ).
IF mac = to_upper( '20956E44B404C4085446139B2B952D77' ).
WRITE:/ 'Test 2B ok'.
ELSE.
WRITE:/ 'Test 2B err'.
ENDIF.
**********
* Test 2C
**********
indata = 'ÄÖÅäöå' && cl_abap_char_utilities=>cr_lf.
l_normalized = me->normalize( indata ).
mac = me->bgc_hmac( indata = l_normalized keyhex = key ).
IF mac = to_upper( '515704694958361678194D51850FF157' ).
WRITE:/ 'Test 2C ok'.
ELSE.
WRITE:/ 'Test 2C err'.
ENDIF.
ENDMETHOD. "test
METHOD normalize.
DATA l_s TYPE string.
DATA l_notallowedchars TYPE string.
DATA cc TYPE REF TO cl_abap_conv_in_ce.
DATA l_repl_char TYPE char1.
DATA l_external_codepage TYPE string VALUE 'ISO-8859-1'.
DATA l_sap_codepage TYPE cpcodepage.
DATA l_abap_encoding TYPE abap_encoding.
DATA l_space TYPE string.
CONCATENATE space space INTO l_space SEPARATED BY space .
CALL FUNCTION 'SCP_CODEPAGE_BY_EXTERNAL_NAME'
EXPORTING
external_name = l_external_codepage
* KIND = 'H'
IMPORTING
sap_codepage = l_sap_codepage
* EXCEPTIONS
* NOT_FOUND = 1
* OTHERS = 2
.
IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
* WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
l_abap_encoding = l_sap_codepage.
l_s = s.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf+0(1) IN l_s WITH co_empty. " remove cr
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf+1(1) IN l_s WITH co_empty. " remove lf
* l_s = me->replace( s = l_s find = 'C9' repl = '40' ). " É --> @
* l_s = me->replace( s = l_s find = 'C5' repl = '5D' ). " Å --> ]
* l_s = me->replace( s = l_s find = 'D6' repl = '5C' ). " Ö --> \
* l_s = me->replace( s = l_s find = 'C4' repl = '5B' ). " Ä --> [
* l_s = me->replace( s = l_s find = 'DC' repl = '5E' ). " Ü --> ^
* l_s = me->replace( s = l_s find = 'E9' repl = '60' ). " é --> `
* l_s = me->replace( s = l_s find = 'E4' repl = '7B' ). " ä --> {
* l_s = me->replace( s = l_s find = 'F6' repl = '7C' ). " ö --> |
* l_s = me->replace( s = l_s find = 'E4' repl = '7D' ). " å --> }
* l_s = me->replace( s = l_s find = 'FC' repl = '7E' ). " ü --> ~
REPLACE ALL OCCURRENCES OF 'É' IN l_s WITH '@'. " C9 40
REPLACE ALL OCCURRENCES OF 'Å' IN l_s WITH ']'. " C5 5D
REPLACE ALL OCCURRENCES OF 'Ö' IN l_s WITH '\'. " D6 5C
REPLACE ALL OCCURRENCES OF 'Ä' IN l_s WITH '['. " C4 5B
REPLACE ALL OCCURRENCES OF 'Ü' IN l_s WITH '^'. " DC 5E
REPLACE ALL OCCURRENCES OF 'é' IN l_s WITH '`'. " E9 60
REPLACE ALL OCCURRENCES OF 'ä' IN l_s WITH '{'. " E4 7B
REPLACE ALL OCCURRENCES OF 'ö' IN l_s WITH '|'. " F6 7C
REPLACE ALL OCCURRENCES OF 'å' IN l_s WITH '}'. " E4 7D
REPLACE ALL OCCURRENCES OF 'ü' IN l_s WITH '~'. " FC 7E
l_notallowedchars = '[' && " // start of range
'^' && " // not
l_space && " // space
'\!' && " // exclamation mark
'\"' && " // double quote
'\#' && " // hash
'\$' && " // dollar
'\%' && " // percent
'\&' && " // ampersand
'\''' && " // single quote
'\(' && " // left parenthesis
'\)' && " // right parenthesis
'\*' && " // star
'\+' && " // plus
'\,' && " // comma
'\-' && " // minus
'\.' && " // dot
'\/' && " // slash
'0-9' && " // range 0-9
'\:' && " // colon
'\;' && " // semicolon
'\<' && " // less than
'\=' && " // equals
'\>' && " // greater than
'\?' && " // question mark
'\@' && " // at
'É' && " // E with apostrophe
'A-Z' && " // range A-Z
'\[' && " // left bracket
'\\' && " // back slash
'\]' && " // right bracket
'\^' && " // caret
'_' && " // under score
'\`' && " // back quote
'a-z' && " // range a-z
'\{' && " // left curly brace
'\|' && " // vertical bar
'\}' && " // right curly brace
'\~' && " // tilde
']'. " // end of range
cc = cl_abap_conv_in_ce=>create( input = 'C3' encoding = l_abap_encoding ).
cc->read( IMPORTING data = l_repl_char ).
* WRITE:/ l_notallowedchars.
* WRITE:/ 's ' , space, l_s.
REPLACE ALL OCCURRENCES OF REGEX l_notallowedchars IN l_s WITH l_repl_char.
* WRITE:/ 's ', space, l_s.
r = l_s.
ENDMETHOD. "normalize
METHOD bgc_hmac.
DATA lw_alg TYPE string VALUE 'SHA256'. " sha1
DATA lw_key TYPE xstring.
DATA l_x TYPE xstring.
DATA l_conv_out TYPE REF TO cl_abap_conv_out_ce.
DATA l_external_codepage TYPE string VALUE 'ISO-8859-1'.
DATA l_sap_codepage TYPE cpcodepage.
DATA l_abap_encoding TYPE abap_encoding.
CALL FUNCTION 'SCP_CODEPAGE_BY_EXTERNAL_NAME'
EXPORTING
external_name = l_external_codepage
* KIND = 'H'
IMPORTING
sap_codepage = l_sap_codepage
EXCEPTIONS
not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
l_abap_encoding = l_sap_codepage.
lw_key = keyhex.
l_conv_out = cl_abap_conv_out_ce=>create( encoding = l_abap_encoding ).
l_conv_out->write( data = indata ).
l_x = l_conv_out->get_buffer( ).
cl_abap_hmac=>calculate_hmac_for_raw( EXPORTING if_algorithm = lw_alg if_key = lw_key if_data = l_x
IMPORTING ef_hmacstring = r ).
r = r+0(32).
ENDMETHOD. "bgc_hmac
METHOD sealopeningrecord.
data l_space type string.
concatenate space space into l_space separated by space.
r = '00' && date && 'HMAC'.
WHILE ( strlen( r ) < 80 ).
r = r && l_space.
ENDWHILE.
ENDMETHOD. "sealopeningrecord
METHOD tamperprotectionrecord.
data l_space type string.
concatenate space space into l_space separated by space.
r = '99' && date && kvv && mac.
WHILE ( strlen( r ) < 80 ).
r = r && l_space.
ENDWHILE.
ENDMETHOD. "tamperprotectionrecord
METHOD createsignature.
DATA l_date TYPE string.
DATA l_length TYPE i.
DATA li_data TYPE STANDARD TABLE OF t_linex.
DATA l_linex TYPE t_linex.
DATA l_x TYPE xstring.
DATA l_s TYPE string.
DATA l_bytes TYPE i.
DATA l_conv_in TYPE REF TO cl_abap_conv_in_ce.
DATA l_conv_out TYPE REF TO cl_abap_conv_out_ce.
DATA l_key TYPE string.
DATA l_keyx TYPE xstring.
DATA l_external_codepage TYPE string VALUE 'ISO-8859-1'.
DATA l_sap_codepage TYPE cpcodepage.
DATA l_abap_encoding TYPE abap_encoding.
DATA l_data TYPE string.
DATA l_filedata TYPE string.
DATA l_line_separator_exists TYPE boolean VALUE abap_false.
DATA l_filedata_normalized TYPE string.
DATA l_mac TYPE string.
DATA l_kvv TYPE string.
DATA l_tamperprotectionrecord TYPE string.
DATA l_line_separator TYPE string.
IF date IS INITIAL.
l_date = sy-datum+2(6).
ELSE.
l_date = date.
ENDIF.
REFRESH li_data.
CLEAR l_length.
cl_gui_frontend_services=>gui_upload(
EXPORTING
filename = keyfile
filetype = 'BIN'
has_field_separator = space
read_by_line = abap_false
IMPORTING
filelength = l_length
CHANGING
data_tab = li_data ).
l_x = me->xtab2xstring( tab = li_data length = l_length ).
l_conv_in = cl_abap_conv_in_ce=>create(
encoding = 'UTF-8' input = l_x ).
* the key is hexencoded
* so remove any cr/lf
l_conv_in->read( IMPORTING data = l_s ).
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf+0(1) IN l_s WITH co_empty. " remove cr
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf+1(1) IN l_s WITH co_empty. " remove lf
l_key = l_s.
l_keyx = l_key.
REFRESH li_data.
CLEAR l_length.
cl_gui_frontend_services=>gui_upload(
EXPORTING
filename = infile
filetype = 'BIN'
has_field_separator = space
read_by_line = abap_false
IMPORTING
filelength = l_length
CHANGING
data_tab = li_data ).
l_x = me->xtab2xstring( tab = li_data length = l_length ).
CALL FUNCTION 'SCP_CODEPAGE_BY_EXTERNAL_NAME'
EXPORTING
external_name = l_external_codepage
* KIND = 'H'
IMPORTING
sap_codepage = l_sap_codepage
EXCEPTIONS
not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
* WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
l_abap_encoding = l_sap_codepage.
l_conv_in = cl_abap_conv_in_ce=>create(
encoding = l_abap_encoding input = l_x ).
l_conv_in->read( IMPORTING data = l_s ).
l_data = l_s.
l_filedata = me->sealopeningrecord( date = l_date ) && ls && l_data.
IF ( substring( val = l_filedata off = ( strlen( l_filedata ) - 1 ) len = 1 ) = cl_abap_char_utilities=>cr_lf+0(1) )
OR ( substring( val = l_filedata off = ( strlen( l_filedata ) - 1 ) len = 1 ) = cl_abap_char_utilities=>cr_lf+1(1) ).
l_line_separator_exists = abap_true.
ENDIF.
l_filedata_normalized = me->normalize( l_filedata ).
* l_conv_out = cl_abap_conv_out_ce=>create( encoding = l_abap_encoding ).
* l_conv_out->write( data = l_filedata_normalized ).
* l_x = l_conv_out->get_buffer( ).
l_mac = me->bgc_hmac( indata = l_filedata_normalized keyhex = l_key ).
l_kvv = me->bgc_hmac( indata = '00000000' keyhex = l_key ).
l_tamperprotectionrecord = me->tamperprotectionrecord( kvv = l_kvv mac = l_mac date = l_date ).
IF l_line_separator_exists = abap_false.
l_line_separator = cl_abap_char_utilities=>cr_lf.
ENDIF.
l_filedata = l_filedata && l_line_separator && l_tamperprotectionrecord && ls.
* make sure to have cr/lf as line separator this is what bgc expects
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf+0(1) IN l_filedata WITH co_empty. " remove all cr
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf+1(1) IN l_filedata WITH cl_abap_char_utilities=>cr_lf. " add cr in front of lf
l_conv_out = cl_abap_conv_out_ce=>create( encoding = l_abap_encoding ).
l_conv_out->write( data = l_filedata ).
l_x = l_conv_out->get_buffer( ).
CALL FUNCTION 'LXE_COMMON_XSTRING_FILE_EXPORT'
EXPORTING
xstring = l_x
filename = outfile.
*
*CALL METHOD cl_gui_frontend_services=>gui_download
* EXPORTING
* bin_filesize =
* filename =
* filetype = 'BIN'
** append = SPACE
** write_field_separator = SPACE
** header = '00'
** trunc_trailing_blanks = SPACE
** write_lf = 'X'
** col_select = SPACE
** col_select_mask = SPACE
** dat_mode = SPACE
** confirm_overwrite = SPACE
** no_auth_check = SPACE
** codepage = SPACE
** ignore_cerr = ABAP_TRUE
** replacement = '#'
** write_bom = SPACE
** trunc_trailing_blanks_eol = 'X'
** wk1_n_format = SPACE
** wk1_n_size = SPACE
** wk1_t_format = SPACE
** wk1_t_size = SPACE
** show_transfer_status = 'X'
** fieldnames =
** write_lf_after_last_line = 'X'
** IMPORTING
** filelength =
* changing
* data_tab =
** 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
* .
*IF sy-subrc <> 0.
** MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
** WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
*ENDIF.
*
ENDMETHOD. "tamperprotectionrecord
METHOD xtab2xstring.
DATA l_linex TYPE t_linex.
DATA l_x TYPE xstring.
DATA l_bytes TYPE i.
DATA l_length TYPE i.
l_length = length.
LOOP AT tab INTO l_linex.
IF l_length > 512.
l_bytes = 512.
ELSE.
l_bytes = l_length.
ENDIF.
CONCATENATE l_x l_linex(l_bytes) INTO l_x IN BYTE MODE.
l_length = l_length - 512.
ENDLOOP.
r = l_x.
ENDMETHOD. "xtab2xstring
ENDCLASS. "zcl_bgc_hmac IMPLEMENTATION
*&---------------------------------------------------------------------*
*& Form test
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM test.
DATA: lo_hmac TYPE REF TO cl_abap_hmac.
DATA: lf_hmac_string TYPE string.
DATA: lw_alg TYPE string VALUE 'sha256'. " sha1
DATA: lw_key TYPE xstring VALUE 'AAAA'.
lo_hmac = cl_abap_hmac=>get_instance( if_algorithm = 'sha256' if_key = lw_key ).
" update HMAC with input
lo_hmac->update( if_data = '010203' ).
" finalise hmac
lo_hmac->final( ).
" String
lf_hmac_string = lo_hmac->to_string( ).
* WRITE:/ lf_hmac_string .
" Base64 representation
lf_hmac_string = lo_hmac->to_base64( ).
* WRITE:/ lf_hmac_string .
DATA l_bgc_hmac TYPE REF TO zcl_bgc_hmac.
CREATE OBJECT l_bgc_hmac.
l_bgc_hmac->test( ).
ENDFORM. "test
*&---------------------------------------------------------------------*
*& Form bgc_hmac
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM bgc_hmac.
DATA l_bgc_hmac TYPE REF TO zcl_bgc_hmac.
DATA l_keyfile TYPE string.
DATA l_outfile TYPE string.
DATA l_infile TYPE string.
DATA l_date TYPE string.
DATA l_ls TYPE string.
l_keyfile = p_keyf.
l_infile = p_inf.
l_outfile = p_outf.
l_date = sy-datum+2(6).
l_ls = cl_abap_char_utilities=>cr_lf.
CREATE OBJECT l_bgc_hmac.
l_bgc_hmac->createsignature( keyfile = l_keyfile infile = l_infile outfile = l_outfile date = l_date ls = l_ls ).
ENDFORM. "bgc_hmac
* methods replace importing value(s) type string value(find) type xstring value(repl) type xstring returning value(r) type string.
*method replace.
* data l_s type string.
* DATA cc TYPE REF TO cl_abap_conv_in_ce.
* DATA l_find_char TYPE char1.
* DATA l_repl_char TYPE char1.
* l_s = s.
* cc = cl_abap_conv_in_ce=>create( input = find encoding = 'UTF-8' ).
* cc->read( IMPORTING data = l_find_char ).
* cc = cl_abap_conv_in_ce=>create( input = repl encoding = 'UTF-8' ).
* cc->read( IMPORTING data = l_repl_char ).
* REPLACE ALL OCCURRENCES OF l_find_char IN l_s WITH l_repl_char.
* r = l_s.
*endmethod.