Instantly share code, notes, and snippets.

Embed
What would you like to do?
Amazon AWS API URL Signature creation with ColdFusion
<cffunction name="awsurl" returntype="string" access="public" output="No">
<cfargument name="Query" type="string" required="true" />
<cfargument name="AWSAccessKeyId" type="string" required="true" />
<cfargument name="SecretKey" type="string" required="true" />
<cfargument name="Host" type="string" default="ec2.amazonaws.com" />
<cfargument name="Methord" type="string" default="GET" />
<cfargument name="URI" type="string" default="/" />
<cfargument name="SignatureVersion" type="string" default="2" />
<cfargument name="Version" type="date" default="2012-04-01" />
<cfargument name="http" type="string" default="https" hint="https|http" />
<!--- add common values --->
<cfset local.Time = dateConvert("local2Utc",now())>
<cfset local.Time = "#DateFormat(local.Time,'yyyy-mm-dd')#T#TimeFormat(local.Time,'HH:mm:ss')#">
<cfset arguments.Query = "#arguments.Query#&Timestamp=#local.Time#&SignatureVersion=#arguments.SignatureVersion#&Version=#arguments.Version#&SignatureMethod=HmacSHA256">
<!--- sort QueryString --->
<cfset arguments.Query = ListToArray(arguments.Query,'&')>
<cfset ArraySort(arguments.Query,'text')>
<!--- prepend AccessKeyID --->
<cfset ArrayPrepend(arguments.Query, "AWSAccessKeyId=#arguments.AWSAccessKeyId#")>
<!--- url encode each values --->
<cfset local.SortedString = ArrayNew(1)>
<cfloop from="1" to="#ArrayLen(arguments.Query)#" index="local.i">
<cfset local.value = arguments.Query[local.i]>
<cfif listlen(local.value,'=') gt 1>
<cfset ArrayAppend(local.SortedString,"#listfirst(local.value,'=')#=#reservedEncod(listlast(local.value,'='))#")>
<cfelse>
<cfset ArrayAppend(local.SortedString,"#local.value#")>
</cfif>
</cfloop>
<!--- create signature string --->
<cfset local.toEncode = "#arguments.Methord##chr(10)##arguments.Host##chr(10)##arguments.URI##chr(10)##ArrayToList(local.SortedString,'&')#">
<cfoutput><pre>#local.toEncode#</pre></cfoutput>
<!--- encode Signature String --->
<cfset local.Signature = URLEncodedFormat(ToBase64(HMAC_SHA256(local.toEncode,arguments.SecretKey)))>
<cfset arguments.Query = ArrayToList(arguments.Query,'&')>
<cfset arguments.Query = "#arguments.http#://#arguments.Host##arguments.URI#?#arguments.Query#&Signature=#local.Signature#">
<cfreturn arguments.Query>
</cffunction>
<cffunction name="reservedEncod" returntype="string" access="public" output="no">
<cfargument name="string" type="string" required="true" />
<cfset local.reserved = "!|##|$|&|'|(|)|*|+|,|/|:|;|=|?|@|[|]| ">
<cfloop list="#local.reserved#" index="local.i" delimiters="|">
<cfif find(local.i,arguments.string)>
<cfset arguments.string = replace(arguments.string,local.i, "%#ucase(FormatBaseN(Asc(local.i),'16'))#", 'all')>
</cfif>
</cfloop>
<cfreturn arguments.string>
</cffunction>
<cffunction name="HMAC_SHA256" returntype="binary" access="public" output="no">
<cfargument name="signMessage" type="string" required="true" />
<cfargument name="signKey" type="string" required="true" />
<cfset local.jMsg = JavaCast("string",arguments.signMessage).getBytes("iso-8859-1") />
<cfset local.jKey = JavaCast("string",arguments.signKey).getBytes("iso-8859-1") />
<cfset local.key = createObject("java","javax.crypto.spec.SecretKeySpec") />
<cfset local.mac = createObject("java","javax.crypto.Mac") />
<cfset local.key = local.key.init(local.jKey,"HmacSHA256") />
<cfset local.mac = local.mac.getInstance(local.key.getAlgorithm()) />
<cfset local.mac.init(local.key) />
<cfset local.mac.update(local.jMsg) />
<cfreturn local.mac.doFinal() />
</cffunction>
@surgiie

This comment has been minimized.

surgiie commented Jan 30, 2017

I cant seem to get HMAC_SHA256 function to generate the proper signature according to the response from amazon. Do you have an updated solution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment