2

I have gone through a number of other related posts on this subject and have been able to replicate them with no problems. However, I cannot get the expected signature result using my own data, no matter what I try to do. I would greatly appreciate any assistance. Here are the API requirements:

  1. Convert the data to sign from an ASCII string to a byte array
  2. Convert your Secret Access Key from a Base64 string to a byte array
  3. Use the byte array created in step 1 as the key for a HMAC-SHA1 signer
  4. Calculate the HMAC-SHA1 hash of the byte array created in step 2. The result will be a byte array
  5. Convert the byte array created in step 3 to a Base64 encoded string

According to the documentation:

I have been unable to get that signature, despite trying a variety of methods from the other posts. For example:

<cffunction name="hmacEncrypt" returntype="binary" access="public" output="false">
    <cfargument name="base64Key" type="string" required="true" default="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==">
    <cfargument name="signMessage" type="string" required="true" default="http://membersuite.com/contracts/IConciergeAPIService/WhoAmI00000000-0000-0000-0000-00000000000011111111-1111-1111-1111-111111111111">
    <cfargument name="encoding" type="string" default="UTF-8">      

     <cfset var messageBytes = JavaCast("string",arguments.signMessage).getBytes(arguments.encoding)>
     <cfset var keyBytes = binaryDecode(arguments.base64Key, "base64")>
     <cfset var key  = createObject("java","javax.crypto.spec.SecretKeySpec")>
     <cfset var mac  = createObject("java","javax.crypto.Mac")>
     <cfset key  = key.init(keyBytes,"HmacSHA512")>
     <cfset mac  = mac.getInstance(key.getAlgorithm())>
     <cfset mac.init(key)>
     <cfset mac.update(messageBytes)>

     <cfreturn mac.doFinal()>
</cffunction>

Dumping the output of that function does not give me any errors, but neither does it match the expected output. Again, I would greatly appreciate any assistance or nudges in the right direction. I think part of my trouble lies in how I am encoding the key and URL string, but I am not sure. Thank you all in advance!

daltec
  • 447
  • 1
  • 5
  • 15

1 Answers1

3

key.init(keyBytes,"HmacSHA512")

Almost. That UDF is hard coded to use "HmacSHA512". Change it to "HmacSHA1", or better yet, make it a function parameter like "encoding".

Example:

<cfset action = "http://membersuite.com/contracts/IConciergeAPIService/WhoAmI">
<cfset associationId = "00000000-0000-0000-0000-000000000000">
<cfset sessionId = "11111111-1111-1111-1111-111111111111">
<cfset stringToSign = action & associationId & sessionId>

<cfset key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==">
<cfset result = binaryEncode(hmacEncrypt(key, stringToSign, "US-ASCII"), "base64")>
<cfset writeDump(result)>

Result:

2zsMYdHb/MJUeTjv5cQl5pBuIqU= 

NB: As of CF10+, HMAC is a now core function:

<cfset resultAsHex = hmac(stringToSign, binaryDecode(key, "base64"), "hmacsha1", "us-ascii")>
<cfset resultAsBase64 = binaryEncode(binaryDecode(resultAsHex, "hex"), "base64")>
<cfset writeDump(resultAsBase64)>
Leigh
  • 28,765
  • 10
  • 55
  • 103
  • Thank you very much, Leigh! This is awesome! Our production server is still on CF9, but I was able to run the HMAC example you provided against CF11 and it worked great! I have requested to upgrade our CF9 machine, which should fix it.The CF10+ example seems so much easier to work with -- can you think of any reasons NOT to go this way? Performance, security, etc? I've already tested some of our existing CF9 code and it seems to work fine. But again, THANK YOU very much for your help! I note you have been able to assist many others with this same issue, so thanks for your patience, too! :-) – daltec Oct 04 '16 at 15:11
  • Thanks for the tip Leigh -- the stringToSign will always be some combination of association ID, session ID and URL of whatever API method we are trying to work with, so hopefully we will be okay. The example you have provided has worked fine in testing, too, using our "real" keys and various API endpoints. So thanks again! Greatly appreciated! – daltec Oct 04 '16 at 16:13