Announcement

Collapse
No announcement yet.

API HMAC Signature Issue

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    API HMAC Signature Issue

    So just a repost, I need to know if the Key that is generated from the API needs to be decoded. When I try to decode it in powershell to be passed into the sha256 has function i get an error that it is not a base 64 length.

    Is the key generated in the pic below already in Base 64 fromat? And if so what should it look like decoded? 2019-10-28_9-08-09.jpg

    #2
    Yes the Signature does need to be decoded before it is passed into your HMAC function. I think the issue here may be that we strip any padding characters from the end of the signature. Some base64 decode functions will break on this. I've seen this specifically with C#.

    Here is an example of how to add the padding characters back:

    Code:
               String key  =  "XXXXXXXXXXXXXXXXXXXXX";
                if ( key.Length % 4 != 0){
                    key = key + new String('=', (4 - (key.Length % 4)));
                }
    This will add equal signs to the end of the string until its length passes a mod 4 check.

    Brennan Heyde
    VP Product
    Miva, Inc.
    [email protected]
    https://www.miva.com

    Comment


      #3
      I still cannot get this to work.

      I hard coded 32 number 1's and converted them to base 64 to get MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE= and added it manually to the API Signature Key. I also did the conversions manually to make sure i was getting the correct string to for a SHA1 hand off which (c66ebd709ec9ee11911ba2718c65a416e194fcc8) Hex Which is xm69cJ7J7hGRG6JxjGWkFuGU/Mg= ...........when it is Base64 Encoded again.


      Here is the results of my header: I HIDE MY API-TOKEN
      Name Value
      ---- -----
      X-Miva-API-Authorization MIVA-HMAC-SHA1 ######################:xm69cJ7J7hGRG6JxjGWkFuGU/Mg=
      Content-Type application/json

      Here is my JSON Body:
      {
      "Function": "Product_Update",
      "Store_Code": "CCTP",
      "product_Inventory": "10",
      "product_code": "SF-81"
      }

      Full Code:
      $apiToken = '######################'
      $key = 'MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE='

      $keyDencoded = [Text.Encoding]::ASCII.GetString([Convert]::FromBase64String($key))

      $hmacsha = New-Object System.Security.Cryptography.SHA1CryptoServiceProv ider
      $hmacHash = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($keyDencoded))
      $hmac = [Convert]::ToBase64String($hmacHash)

      [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
      $headers = @{}
      $headers["Content-Type"] = "application/json"
      $headers["X-Miva-API-Authorization"] = "MIVA-HMAC-SHA1" + " " + $apiToken + ":" + $hmac
      $body = @{
      Store_Code = 'CCTP'
      Function = 'Product_Update'
      product_code = $ProductCode
      product_Inventory = $CurrentStock


      }
      $body = $body | ConvertTo-Json

      $uri = "https://www.crazycrow.com/mm5/json.mvc"

      IWR -UseBasicParsing -Method POST -Uri $uri -headers $headers -Body $body


      This format works for making an API Call without the Signature.

      I need further assistance.






      Comment


        #4
        You need to use the HMAC functions to sign the body of the request and include the resulting signature in the headers. Looks like you are just decoding the key then creating a sha1 hash of the key itself.

        What you want to do is something more like this (note: I didn't test this):

        PHP Code:
        $apiToken '######################'
        $key 'MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE='

        $keyDecoded = [Text.Encoding]::ASCII.GetString([Convert]::FromBase64String($key))

        $hmac = New-Object System.Security.Cryptography.HMACSHA1($keyDecoded)

        # OR FOR SHA256
        # $hmac = New-Object System.Security.Cryptography.HMACSHA256($keyDecoded)

        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

        $body 
        = @{
        Store_Code 'CCTP'
        Function = 'Product_Update'
        product_code $ProductCode
        product_Inventory 
        $CurrentStock


        }
        $body $body ConvertTo-Json

        $signature 
        $hmac.ComputeHash([Text.Encoding]::ASCII.GetBytes($body))
        $signature = [Convert]::ToBase64String($signature)

        $headers = @{}
        $headers["Content-Type"] = "application/json"
        $headers["X-Miva-API-Authorization"] = "MIVA-HMAC-SHA1" " " $apiToken ":" $signature

        # OR FOR SHA256
        # $headers["X-Miva-API-Authorization"] = "MIVA-HMAC-SHA256" + " " + $apiToken + ":" + $signature

        $uri "https://www.crazycrow.com/mm5/json.mvc"

        IWR -UseBasicParsing -Method POST -Uri $uri -headers $headers -Body $body 
        Also, if you configure your API token to require timestamps to prevent replay attacks you will also need to include the Miva_Request_Timestamp field in your body JSON request with the current unix timestamp in integer format
        Last edited by ghassani; 10-29-19, 10:26 AM.

        Comment


          #5
          So I am still confused on what I am suppose to be doing with the keyDecoded that I have. Does it need to be SHA256 hashed as well as the JSON body?

          your code it just has (keyDecoded) out beside $hmac? what are you trying to do there so I can translate in .Net terms.($hmac = New-Object System.Security.Cryptography.HMACSHA1($keyDecoded) )

          here is my updated code and i generated a new token and key.


          $apiToken = '#################################'
          $key = 'U4UFkwL08PAyG6xPJsp3mCt3T/d/jvn/rmZEV/kgOTw='


          $keyDencoded = [Text.Encoding]::ASCII.GetString([Convert]::FromBase64String($key))


          $hmacsha = New-Object System.Security.Cryptography.SHA256Managed
          $toHash = [System.Text.Encoding]::UTF8.GetBytes($body)
          $hmacHash = $hmacsha.ComputeHash($toHash)
          $hmac = [Convert]::ToBase64String($hmacHash)

          [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
          $headers = @{
          'Content-Type' = 'application/json'
          'X-Miva-API-Authorization' = 'MIVA-HMAC-SHA256' + ' ' + $apiToken + ':' + $hmac
          }

          $body = @{
          Store_Code = 'CCTP'
          Function = 'Product_Update'
          product_code = 'testmiva_s'
          product_Inventory = '10'
          }


          $body = $body | ConvertTo-Json

          $uri = "https://www.crazycrow.com/mm5/json.mvc"

          IRM -Method POST -Uri $uri -headers $headers -Body $body

          Comment


            #6
            You need to use the hmac algorithm to sign the request's body content, not create a SHA1 or SHA256 hash of the key. The whole point of this is to prove that you are the key owner by signing and encrypting the SHA 1/256 hash of the actual data being sent. Then on miva's end we validate the content that was sent and signed using the same key associated with the api token.

            Here is a working example I tested on my mac (PowerShell 6.2.3), just replace the parameters at the top with your own

            PHP Code:
            $apiToken 'MY_TOKEN'
            $signingKey 'MY_SIGNING_KEY'
            $storeCode 'MY_STORE_CODE'
            $url "https://www.crazycrow.com/mm5/json.mvc"
            $includeTimestamp 

            # Add back padding to signing key
            if ( -not $signingKey.Length -eq 0)
            {
                
            $signingKey $signingKey.PadRight$signingKey.Length + (- ($signingKey.Length 4)), '=')
            }

            # Create a message to sign with the hmac algorithm, in this case it will be 
            # our JSON request body

            $body = @{
                
            Store_Code $storeCode

                
            # Your parameters
                
            Function = 'Product_Update'    
            }

            if ( 
            $includeTimestamp )
            {
                
            $body["Miva_Request_Timestamp"] = [DateTimeOffset]::Now.ToUnixTimeSeconds() 
            }

            $body $body ConvertTo-Json

            # Now that we have the body content we are sending we can create the hash

            # create an instance of C# HMAC SHA256 implementation
            # passing the decoded signing key byte array as the key

            $key = [System.Convert]::FromBase64String($signingKey)
            $hmac = [System.Security.Cryptography.HMACSHA256]::new($key)

            # Sign the body with the HMAC algorithm

            $signature $hmac.ComputeHash([Text.Encoding]::ASCII.GetBytes($body))
            $signature = [Convert]::ToBase64String($signature)

            # now create your headers

            $headers = @{
                
            "Content-Type" "application/json"
                "X-Miva-API-Authorization" 
            "MIVA-HMAC-SHA256" " " $apiToken ":" $signature
            }

            #Write-Output "Signature: " $signature
            #Write-Output "Headers: " $headers
            #Write-Output "Body: " $body

            # now send your request
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

            IWR 
            -UseBasicParsing -Method POST -Uri $url -headers $headers -Body $body 

            Comment


              #7
              Thanks, I have been trying to figure this out since Sunday evening. I had a few things wrong on my code, I definitely have tried an iteration of what you had for the key and the HMAC at one point of time, but after working through my code I figured out what was really killing me. My $body = $body | ConvertTo-Json was after my conversion of the hmac. So i was passing bad data for the body into the hmac function.

              Thanks for the help
              Chris

              Comment

              Working...
              X