<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>Question Re: HMAC authentication does not work in Technology Q&amp;A</title>
    <link>https://community.sap.com/t5/technology-q-a/solved-hmac-authentication-does-not-work/qaa-p/13922460#M4890317</link>
    <description>&lt;P&gt;Ok, at last I found out what was wrong:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;for starters, we need the "&lt;SPAN&gt;calculate_hmac_for_raw"&lt;/SPAN&gt; method&lt;/LI&gt;&lt;LI&gt;next, both this and the "&lt;SPAN&gt;calculate_hmac_for_char" method will perform SHA256 on the given key internally, it must NOT be done before!&lt;/SPAN&gt;&lt;/LI&gt;&lt;LI&gt;&lt;SPAN&gt;last, if more than one iteration is required, the output should be manually copied over to the input: using the same variable is bad! (unit test for the win!)&lt;/SPAN&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;LI-CODE lang="abap"&gt;  METHOD build_hmac_response.
    DATA lv_hmacstring    TYPE string.
    DATA lv_hmacb64string TYPE string.
    DATA lv_hmacxstring   TYPE xstring.

    DATA(lv_datax) = cl_abap_hmac=&amp;gt;string_to_xstring( if_input = if_data ).
    DO if_iterations TIMES.
      TRY.
          cl_abap_hmac=&amp;gt;calculate_hmac_for_raw( EXPORTING if_algorithm     = c_algo_sha256
                                                          if_key           = if_key
                                                          if_data          = lv_datax
                                                IMPORTING ef_hmacstring    = lv_hmacstring
                                                          ef_hmacxstring   = lv_hmacxstring
                                                          ef_hmacb64string = lv_hmacb64string ).
* Note: importing directly "lv_datax" clobbers the returns and will give the wrong result;
* to support the (yet untested) case of iterations &amp;gt; 1 just copy the string before looping!
          lv_datax = lv_hmacxstring.
        CATCH cx_abap_message_digest INTO DATA(e_txt).
          WRITE / e_txt-&amp;gt;get_text( ).
      ENDTRY.
    ENDDO.
    ef_result = lv_hmacstring.
    ef_resultx = lv_hmacxstring.
    ef_resultb = lv_hmacb64string.

  ENDMETHOD.&lt;/LI-CODE&gt;&lt;P&gt;&lt;SPAN&gt;And corresponding test method:&lt;/SPAN&gt;&lt;/P&gt;&lt;LI-CODE lang="abap"&gt;  METHOD _02_hmac_1_iter_no_sha.
    DATA l_act_string TYPE string.

    TRY.
* MEMO: we must NOT run SHA256 on the key, the HMAC method will take care of that!
        DATA(lv_keyx) = cl_abap_hmac=&amp;gt;string_to_xstring( if_input = |{ c_password }{ c_salt }| ).
      CATCH cx_abap_message_digest.
    ENDTRY.

    mo_cut-&amp;gt;build_hmac_response( EXPORTING if_key        = lv_keyx
                                           if_iterations = 1
                                           if_data       = c_testdata
                                 IMPORTING ef_result     = l_act_string ).

    cl_abap_unit_assert=&amp;gt;assert_equals( exp = c_hmac_of_pwd_salt_testdata
                                        act = l_act_string
                                        msg = `HMAC with RAW password/salt does not match hash!` ).
  ENDMETHOD.&lt;/LI-CODE&gt;&lt;P&gt;&lt;SPAN&gt;All is well &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/SPAN&gt;&lt;/P&gt;</description>
    <pubDate>Tue, 29 Oct 2024 10:13:16 GMT</pubDate>
    <dc:creator>abo</dc:creator>
    <dc:date>2024-10-29T10:13:16Z</dc:date>
    <item>
      <title>[solved] HMAC authentication does not work</title>
      <link>https://community.sap.com/t5/technology-q-a/solved-hmac-authentication-does-not-work/qaq-p/13904862</link>
      <description>&lt;P&gt;I need to talk to a server using REST with HMAC authentication. Before dealing with the server, I thought I would first write and validate the HMAC part and... that's exactly where I am stuck: the values I calculate in SAP are different from those I get using &lt;A href="https://www.liavaag.org/English/SHA-Generator/HMAC/" target="_blank" rel="noopener"&gt;online calculators.&lt;/A&gt;&lt;/P&gt;&lt;P&gt;Here is my utility class:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="abap"&gt;CLASS zcl_auth_util DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    CONSTANTS c_algo_sha256 TYPE string VALUE `SHA256`.

    CLASS-METHODS build_key
      IMPORTING if_password TYPE string
                if_salt     TYPE string
      EXPORTING ef_key      TYPE xstring.

    CLASS-METHODS build_hmac_response
      IMPORTING if_key        TYPE xstring
                if_iterations TYPE i
                if_data       TYPE string
      EXPORTING ef_result     TYPE string
                ef_resultx    TYPE xstring
                ef_resultb    TYPE string.
ENDCLASS.



CLASS ZCL_AUTH_UTIL IMPLEMENTATION.


* &amp;lt;SIGNATURE&amp;gt;---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_AUTH_UTIL=&amp;gt;BUILD_HMAC_RESPONSE
* +-------------------------------------------------------------------------------------------------+
* | [---&amp;gt;] IF_KEY                         TYPE        XSTRING
* | [---&amp;gt;] IF_ITERATIONS                  TYPE        I
* | [---&amp;gt;] IF_DATA                        TYPE        STRING
* | [&amp;lt;---] EF_RESULT                      TYPE        STRING
* | [&amp;lt;---] EF_RESULTX                     TYPE        XSTRING
* | [&amp;lt;---] EF_RESULTB                     TYPE        STRING
* +--------------------------------------------------------------------------------------&amp;lt;/SIGNATURE&amp;gt;
  METHOD build_hmac_response.
    DATA lv_hmacxstring   TYPE xstring.
    DATA lv_hmacb64string TYPE string.

    DATA(lv_data) = if_data.
    DO if_iterations TIMES.
      TRY.
          cl_abap_hmac=&amp;gt;calculate_hmac_for_char( EXPORTING if_algorithm     = c_algo_sha256
                                                           if_key           = if_key
                                                           if_data          = lv_data
                                                 IMPORTING ef_hmacstring    = lv_data
                                                           ef_hmacxstring   = lv_hmacxstring
                                                           ef_hmacb64string = lv_hmacb64string ).
        CATCH cx_root INTO DATA(e_txt).
          WRITE / e_txt-&amp;gt;get_text( ).
      ENDTRY.
    ENDDO.
    ef_result = lv_data.
    ef_resultx = lv_hmacxstring.
    ef_resultb = lv_hmacb64string.
  ENDMETHOD.


* &amp;lt;SIGNATURE&amp;gt;---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_AUTH_UTIL=&amp;gt;BUILD_KEY
* +-------------------------------------------------------------------------------------------------+
* | [---&amp;gt;] IF_PASSWORD                    TYPE        STRING
* | [---&amp;gt;] IF_SALT                        TYPE        STRING
* | [&amp;lt;---] EF_KEY                         TYPE        XSTRING
* +--------------------------------------------------------------------------------------&amp;lt;/SIGNATURE&amp;gt;
  METHOD build_key.
    DATA(lv_keyx) = cl_abap_hmac=&amp;gt;string_to_xstring( |{ if_password }{ if_salt }| ).

    TRY.
        DATA(lr_digest) = cl_abap_message_digest=&amp;gt;get_instance( if_algorithm = c_algo_sha256 ).
        lr_digest-&amp;gt;update( if_data = lv_keyx ).
        lr_digest-&amp;gt;digest( ).
        ef_key = cl_abap_hmac=&amp;gt;string_to_xstring( lr_digest-&amp;gt;to_string( ) ).
      CATCH cx_abap_message_digest.  "
    ENDTRY.
  ENDMETHOD.
ENDCLASS.&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;And this is the test class:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="abap"&gt;*"* use this source file for your ABAP unit test classes
CLASS ltc_auth_util_test DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.

  PUBLIC SECTION.
    METHODS _01_key_hash         FOR TESTING.
    METHODS _02_hmac_1_iter_no_sha FOR TESTING.
    METHODS _03_hmac_1_iter_with_sha FOR TESTING.

  PRIVATE SECTION.
    CLASS-METHODS class_setup.
    CLASS-METHODS class_teardown.

    METHODS setup.
    METHODS teardown.

    CONSTANTS c_password TYPE string VALUE `this_is_a_test_password`.
    CONSTANTS c_salt TYPE string VALUE `N1cbsxNB2X1uR0i20YmE9iV9L5icQtXQQ5V+7quww24VK32IStgnMhp/BIcgIoFH7FTUDaYHyZvsVrLRZRH4Nw==`.
    CONSTANTS c_pwd_salt_sha256 TYPE string VALUE `55557945A262E5FB6C553CBA833D0F75A11D42B17EEF27C7288B2A6C8B7CB930`.
    CONSTANTS c_testdata TYPE string VALUE `this is a test message to be signed`.
    CONSTANTS c_hmac_of_pwd_salt_testdata TYPE string VALUE `5B78CD8ADA9CABC8A65AAF5B0AD8648DD021FF1C285BEA51A3DDD6CC2D9D7A07`.

    DATA mo_cut TYPE REF TO zcl_auth_util.
ENDCLASS.


CLASS ltc_auth_util_test IMPLEMENTATION.
  METHOD _01_key_hash.
    DATA l_exp TYPE xstring.
    DATA l_act TYPE xstring.

    TRY.
        l_exp = cl_abap_hmac=&amp;gt;string_to_xstring( if_input = c_pwd_salt_sha256 ).
      CATCH cx_abap_message_digest.  "
    ENDTRY.

    mo_cut-&amp;gt;build_key(
      EXPORTING if_password = c_password
                if_salt     = c_salt
      IMPORTING ef_key      = l_act ).
    cl_abap_unit_assert=&amp;gt;assert_equals( exp = l_exp
                                        act = l_act
                                        msg = `Hashed key (pwd/salt) does not match expected value` ).
  ENDMETHOD.

  METHOD _02_hmac_1_iter_no_sha.
    DATA l_act_string TYPE string.

    TRY.
        DATA(lv_keyx) = cl_abap_hmac=&amp;gt;string_to_xstring(
* This is the correct SHA256 of the password/salt from the first test
*       if_input = c_pwd_salt_sha256
* but first we try with raw password+salt
        if_input = |{ c_password }{ c_salt }| ).

      CATCH cx_abap_message_digest.  "
    ENDTRY.

    mo_cut-&amp;gt;build_hmac_response( EXPORTING if_key        = lv_keyx
                                           if_iterations = 1
                                           if_data       = c_testdata
                                 IMPORTING ef_result     = l_act_string ).

    cl_abap_unit_assert=&amp;gt;assert_differs( exp = c_hmac_of_pwd_salt_testdata
                                        act = l_act_string
                                        msg = `HMAC with RAW password/salt matches hash, that's odd!` ).
  ENDMETHOD.

  METHOD _03_hmac_1_iter_with_sha.
    DATA l_act_string TYPE string.

    TRY.
        DATA(lv_keyx) = cl_abap_hmac=&amp;gt;string_to_xstring(
* This is the correct SHA256 of the password/salt from the first test
                            if_input = c_pwd_salt_sha256 ).
      CATCH cx_abap_message_digest.  "
    ENDTRY.

    mo_cut-&amp;gt;build_hmac_response( EXPORTING if_key        = lv_keyx
                                           if_iterations = 1
                                           if_data       = c_testdata
                                 IMPORTING ef_result     = l_act_string ).

    cl_abap_unit_assert=&amp;gt;assert_equals( exp = c_hmac_of_pwd_salt_testdata
                                        act = l_act_string
                                        msg = 'HMAC with SHA256 of password/salt does not match expected hash' ).
  ENDMETHOD.


  METHOD class_setup.
  ENDMETHOD.

  METHOD class_teardown.
  ENDMETHOD.

  METHOD setup.
    mo_cut = NEW #( ).
  ENDMETHOD.

  METHOD teardown.
    CLEAR mo_cut.
  ENDMETHOD.
ENDCLASS.&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Test 1 and 2 pass, test 3 fails. Actually, test 2 was an afterthought: maybe the HMAC class is already doing a SHA256 on the key and I do not have to do it again? But no, apparently that is not the case and I am still clueless as to what might be the issue here.&lt;/P&gt;&lt;P&gt;Regardless of whether the remote server is expecting the key to be the SHA256 of password+salt or just of the password, it would be nice if my calculated values matched what the online calculators say &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/P&gt;&lt;P&gt;Any ideas? The code above is complete and runs ok in the latest Docker image for sure (but even at the office using a relatively ancient release, for that matter)&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 29 Oct 2024 10:13:51 GMT</pubDate>
      <guid>https://community.sap.com/t5/technology-q-a/solved-hmac-authentication-does-not-work/qaq-p/13904862</guid>
      <dc:creator>abo</dc:creator>
      <dc:date>2024-10-29T10:13:51Z</dc:date>
    </item>
    <item>
      <title>Re: HMAC authentication does not work</title>
      <link>https://community.sap.com/t5/technology-q-a/solved-hmac-authentication-does-not-work/qaa-p/13922460#M4890317</link>
      <description>&lt;P&gt;Ok, at last I found out what was wrong:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;for starters, we need the "&lt;SPAN&gt;calculate_hmac_for_raw"&lt;/SPAN&gt; method&lt;/LI&gt;&lt;LI&gt;next, both this and the "&lt;SPAN&gt;calculate_hmac_for_char" method will perform SHA256 on the given key internally, it must NOT be done before!&lt;/SPAN&gt;&lt;/LI&gt;&lt;LI&gt;&lt;SPAN&gt;last, if more than one iteration is required, the output should be manually copied over to the input: using the same variable is bad! (unit test for the win!)&lt;/SPAN&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;LI-CODE lang="abap"&gt;  METHOD build_hmac_response.
    DATA lv_hmacstring    TYPE string.
    DATA lv_hmacb64string TYPE string.
    DATA lv_hmacxstring   TYPE xstring.

    DATA(lv_datax) = cl_abap_hmac=&amp;gt;string_to_xstring( if_input = if_data ).
    DO if_iterations TIMES.
      TRY.
          cl_abap_hmac=&amp;gt;calculate_hmac_for_raw( EXPORTING if_algorithm     = c_algo_sha256
                                                          if_key           = if_key
                                                          if_data          = lv_datax
                                                IMPORTING ef_hmacstring    = lv_hmacstring
                                                          ef_hmacxstring   = lv_hmacxstring
                                                          ef_hmacb64string = lv_hmacb64string ).
* Note: importing directly "lv_datax" clobbers the returns and will give the wrong result;
* to support the (yet untested) case of iterations &amp;gt; 1 just copy the string before looping!
          lv_datax = lv_hmacxstring.
        CATCH cx_abap_message_digest INTO DATA(e_txt).
          WRITE / e_txt-&amp;gt;get_text( ).
      ENDTRY.
    ENDDO.
    ef_result = lv_hmacstring.
    ef_resultx = lv_hmacxstring.
    ef_resultb = lv_hmacb64string.

  ENDMETHOD.&lt;/LI-CODE&gt;&lt;P&gt;&lt;SPAN&gt;And corresponding test method:&lt;/SPAN&gt;&lt;/P&gt;&lt;LI-CODE lang="abap"&gt;  METHOD _02_hmac_1_iter_no_sha.
    DATA l_act_string TYPE string.

    TRY.
* MEMO: we must NOT run SHA256 on the key, the HMAC method will take care of that!
        DATA(lv_keyx) = cl_abap_hmac=&amp;gt;string_to_xstring( if_input = |{ c_password }{ c_salt }| ).
      CATCH cx_abap_message_digest.
    ENDTRY.

    mo_cut-&amp;gt;build_hmac_response( EXPORTING if_key        = lv_keyx
                                           if_iterations = 1
                                           if_data       = c_testdata
                                 IMPORTING ef_result     = l_act_string ).

    cl_abap_unit_assert=&amp;gt;assert_equals( exp = c_hmac_of_pwd_salt_testdata
                                        act = l_act_string
                                        msg = `HMAC with RAW password/salt does not match hash!` ).
  ENDMETHOD.&lt;/LI-CODE&gt;&lt;P&gt;&lt;SPAN&gt;All is well &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Tue, 29 Oct 2024 10:13:16 GMT</pubDate>
      <guid>https://community.sap.com/t5/technology-q-a/solved-hmac-authentication-does-not-work/qaa-p/13922460#M4890317</guid>
      <dc:creator>abo</dc:creator>
      <dc:date>2024-10-29T10:13:16Z</dc:date>
    </item>
  </channel>
</rss>

