Reputation: 43
I'm working on a ColdFusion site that needs to talk to another system through Webservices. For the other system I have a sample in PHP about how to generate a SHA512 based hash, and I'm trying to replicate the same function in ColdFusion but it is just not working.
The sample includes a string and key, and the expected encoded outcome. But I do not get the same encoded string with ColdFusion. Maybe I'm missing a ToBase64 or another conversion function somewhere, but I'm out of ideas and really need help to get this working.
Any help would be soo much appreciated.
//signature to acquire a session
$apiId = '1lie8ficql9h5';
$apiSecret = 'j6hriaKY2iZi+Y2uo9JJldmO1Bq79XB8d1v2uHzAK0Zvy972mIs8ThsJSQeDlZJz+HzmLD6Q1MUZb5X1Zf9MzQ==';
//build the string to sign
//note the order of the entries is important.
//The http headers must be in alphabetical order by key name
$httpMethod = 'POST';
$apiKey = 'x-csod-api-key:'.$apiId;
$httpUrl = '/services/api/sts/session';
date_default_timezone_set('UTC');
$date = 'x-csod-date:'.date('Y-m-d').'T'.date('H:i:s').'.000';
$stringToSign = $httpMethod."\n".$apiKey."\n".$date."\n".$httpUrl;
/* produces the following string:
* POST\nx-csod-api-key:1lie8ficql9h5\nx-csod-date:2015-09-08T11:27:32.000\n/services/api/sts/session
*/
//Generate the signature
$secretKey = base64_decode($apiSecret);
$signature = base64_encode(hash_hmac('sha512', $stringToSign, $secretKey, true));
/*
* signature produced:
* 3x5ETGSoqJa4vLl8gOFzdhxReOS0k8Nk2CpKVFN2A60ItF8wfP2tr+GUY2mELXjL90B57B5imLIrzou3ZQMfqQ==
*/
<cfoutput>
<cfset api_id= "1lie8ficql9h5">
<cfset api_secret= "j6hriaKY2iZi+Y2uo9JJldmO1Bq79XB8d1v2uHzAK0Zvy972mIs8ThsJSQeDlZJz+HzmLD6Q1MUZb5X1Zf9MzQ==">
<cfset api_string= "POST\nx-csod-api-key:1lie8ficql9h5\nx-csod-date:2015-09-08T11:27:32.000\n/services/api/sts/session">
<cfset temp_key= ToString(ToBinary( api_secret))>
<cfset temp_signature= HMAC( api_string, temp_key, "HMACSHA512", "UTF-8")>
<cfset temp_signature1= ToBase64( temp_signature)>
api_string:<br> #api_string#<br><br>
temp_signature:<br> #temp_signature#<br>
temp_signature1:<br> #temp_signature1#<br><br>
EXPECTED: (Copied from the PHP Sample code)<br>
3x5ETGSoqJa4vLl8gOFzdhxReOS0k8Nk2CpKVFN2A60ItF8wfP2tr+GUY2mELXjL90B57B5imLIrzou3ZQMfqQ==
</cfoutput>
Upvotes: 4
Views: 168
Reputation: 7833
There are two things that go wrong here:
hmac()
in ColdFusion returns the hash in hexadecimal. hmac(..., true)
in PHP returns the hash as binary.\n
in the message you want to hash. ColdFusion does not automatically convert them. PHP does (when enclosed in double quotes "
).Solution:
binaryDecode(hmac, "HEX")
to convert the hash to binary in ColdFusion.#chr(10)#
instead of \n
in ColdFusion.Here is a version for both languages:
PHP:
$apiSecret = 'j6hriaKY2iZi+Y2uo9JJldmO1Bq79XB8d1v2uHzAK0Zvy972mIs8ThsJSQeDlZJz+HzmLD6Q1MUZb5X1Zf9MzQ==';
$stringToSign = "POST\nx-csod-api-key:1lie8ficql9h5\nx-csod-date:2015-09-08T11:27:32.000\n/services/api/sts/session";
$secretKey = base64_decode($apiSecret);
$signature = base64_encode(
hash_hmac('sha512', $stringToSign, $secretKey, true)
);
echo $signature;
ColdFusion:
<cfset apiSecret = 'j6hriaKY2iZi+Y2uo9JJldmO1Bq79XB8d1v2uHzAK0Zvy972mIs8ThsJSQeDlZJz+HzmLD6Q1MUZb5X1Zf9MzQ=='>
<cfset stringToSign = 'POST#chr(10)#x-csod-api-key:1lie8ficql9h5#chr(10)#x-csod-date:2015-09-08T11:27:32.000#chr(10)#/services/api/sts/session'>
<cfset secretKey = toBinary(apiSecret)>
<cfset signature = toBase64(
binaryDecode(
hmac(stringToSign, secretKey, 'HMACSHA512'),
'HEX'
)
)>
<cfoutput>#signature#</cfoutput>
Upvotes: 5