Skip to content

Instantly share code, notes, and snippets.

@cflove cflove/gist:4716338
Created Feb 5, 2013

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.

Copy link

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
You can’t perform that action at this time.