earthtrip

earthtrip

Port of Java to Elixir for HMAC signature generation causes invalid security header error in Apigee API

Hi all

I’m banging my head against the wall on this… I have to port a bit of Java code over to Elixir/erlang and can’t seem to get this working… I mean I can get my code to output base64 encoded strings but the server is rejecting them as invalid.

This is the function in question:

    private static String generateMacSignature(final String payload, final String resourceURI, final String host,
					       final String port, final String macId, final String key, final String httpMethod) {
    	String signature = null;
    	try {
	    String timestamp = Long.toString(System.currentTimeMillis()).trim();
	    String nonce = UUID.randomUUID().toString().trim();
	    String bodyHash = encode(payload, key);
	    // Create MAC input string
	    String macInput = timestamp + "\n" + nonce + "\n" + httpMethod + "\n" + resourceURI + "\n" + host + "\n"
		+ port + "\n" + bodyHash + "\n";
	    String encodedMacInput = encode(macInput, key);
	    String macRequestAuthFmt = "MAC id={0},ts={1},nonce={2},bodyhash={4},mac={3}";
	    String[] authHeaderInputs = new String[]{"\"" + macId + "\"", "\"" + timestamp + "\"", "\"" + nonce + "\"",
						     "\"" + encodedMacInput + "\"", "\"" + bodyHash + "\""};
	    signature = MessageFormat.format(macRequestAuthFmt, authHeaderInputs);
    	} catch (Exception e) {
	    System.err.println("Exception while generating MAC Signature: " + e.getMessage());
    	}
    	return signature;
    }

    private static String encode(String data, String key) throws Exception {
    	String encodedData = null;
    	try {
	    // get an HmacSHA256 signing- key from the raw key bytes
	    SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA256");
	    // get an HmacSHA256Mac instance and initialize with the signing key
	    Mac mac = Mac.getInstance("HmacSHA256");
	    mac.init(signingKey);
	    // compute the hmac on input data bytes
	    byte[] rawHmac = mac.doFinal(data.getBytes());
	    // base64-encode the hmac
	    encodedData = new String(Base64.encodeBase64(rawHmac)).replace("\r\n", StringUtils.EMPTY);
    	} catch (Exception e) {
	    throw e;
    	}
    	return encodedData;
    }

I’ve basically tried a few different variants of this based on some posts I’ve seen here and SO as well as asking GPT4 and haven’t been able to get the server integration to work.

Here’s my basic function but I’m not completely sure how those Java libraries work or what they’re doing that’s different.

  defp encode(data, secret) do
    :crypto.mac(:hmac, :sha256, secret, data) |> Base.encode64
  end

Thanks for any assistance!

Most Liked

al2o3cr

al2o3cr

To clarify, I meant “good” and “bad” outputs for the same request. Those two don’t have the same bodyhash value… :thinking:

What we can spot from the “good” sample:

  • the output is expected in the standard base64 alphabet (with +, versus the “url-safe” one that substitutes -)
  • the output should include base64 padding (the trailing =s)

Together those mean that Elixir’s Base.encode64 will work with no additional options.

HOWEVER

The base64 flavor is the least of the problems. HMAC is explicitly designed to change a lot (and unpredictably) for even a single-bit difference in its input, so any mis-formatting before the HMAC will produce wrong values that don’t provide any clues to the problem.

This isn’t a “try it until it works” situation; the results of the failures aren’t going to give any feedback about why things are wrong. Can you post a link to the documentation for the specific API you’re trying to call?

As for troubleshooting the whole thing, you’ll want to capture the inputs & outputs of the pieces of generateMacSignature for comparison with the reimplementation:

  • what is the value of payload? Your Elixir code should be able to produce an identical bodyhash value for the same payload.
  • what is the exact value (newlines included!) of macInput? Again, your Elixir code needs to produce the same bytes given the same inputs
Hermanverschooten

Hermanverschooten

I would start by printing all intermediate values in both the original and the elixir code, arriving with what is passed to the base64 encoding, checking for differences along the way. eg what does the SecretKeySpec do in regards with just passing the key to :crypto.mac/4, etc.

Where Next?

Popular in Questions Top

Tee
can someone please explain to me how Enum.reduce works with maps
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement