How does one generate an HMAC string in Elixir?

Zach Garwood picture Zach Garwood · Nov 22, 2014 · Viewed 9.9k times · Source

I'm attempting to write an Amazon Product Advertising API client in Elixir. The developer guide describes the process for signing an API request in which the an HMAC-SHA26 hash must be created using the request and the "Secret Access Key." This is the function I wrote to handle signing the request:

defp sign_request(url) do
  url_parts = URI.parse(url)
  request = "GET\n" <> url_parts.host <> "\n" <> url_parts.path <> "\n" <> url_parts.query
  url <> "&Signature=" <> :crypto.hmac(:sha256, 'ThisIsMySecretAccessKey', request)
end

The url passed into the function looks something like this: http://webservice.amazon.com/onca/xml?AssociateTag=ThisIsMyAssociateTag&AWSAccessKeyId=ThisIsMyAWSAccessKeyId&Keywords=stuff&Operation=ItemSearch&SearchIndex=Apparel&Service=AWSECommerceService&Timestamp=2014-11-22T12%3A00%3A00Z&Validate=True&Version=2013-08-01

The issue I'm having is that, while:crypto.hmac/3 returns a binary, that binary is not a string; passing the return value to String.valid?/1 returns false. So, I am unable to concatenate the return value onto the end of the url string to sign the request.

Am I using :crypto.hmac/3 incorrectly? Is there something I'm missing? Is there an alternate way I should be going about this?

Answer

Igor Kapkov picture Igor Kapkov · Nov 23, 2014

When you using :crypto.hmac/3 its return base 16 integer in binary format, your problem could be solved like this:

:crypto.hmac(:sha256, "key", "The quick brown fox jumps over the lazy dog")
|> Base.encode16

This is match example from https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Examples_of_HMAC_.28MD5.2C_SHA1.2C_SHA256.29