daltec
daltec

Reputation: 547

Unable to generate valid signature for API using ColdFusion and HMAC-SHA1

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!

Upvotes: 2

Views: 387

Answers (1)

Leigh
Leigh

Reputation: 28873

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)>

Upvotes: 3

Related Questions