How does one generate an HMAC string in Elixir?
Asked Answered
K

1

21

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?

Kenya answered 22/11, 2014 at 20:50 Comment(1)
You may also want to look into using string interpolation in Elixir. elixir-lang.org/getting_started/2.html#2.4-strings May simplify your code a bit.Novobiocin
R
47

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

:crypto.mac(: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

Relations answered 23/11, 2014 at 3:34 Comment(4)
Or maybe use Base.encode16 (:crypto.hmac(:sha256, "key", "The quick brown fox jumps over the lazy dog") |> Base.encode16)Neile
I used the solution that @Neile proposed in his comment because it is one less line and it's easier to read.Kenya
That's not the same as what's in the answer. The difference is the same as between hmac_bytes |> Base.encode16 and hmac_bytes |> Base.encode16 |> Base.encode16. Encoding twice seems out of place.Rhythmics
This will be :crypto.mac(:hmac, :sha256, priv_key, content) |> Base.encode16 in the future according to erlang.org/doc/apps/crypto/new_api.html#the-new-apiJodijodie

© 2022 - 2024 — McMap. All rights reserved.