4

I've been trying to implement a client for Kraken private API (https://www.kraken.com/help/api) and because I've been running into some issues with that, I've been trying to access that same API with cURL.

However, I can't get for the life of me get it to work and I think I may not be using the right command line tools to generate the hashes and digests.

When accessing the private API the following headers need to be added to the request:

API-Key = «key»
API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded «secret»

On the command line I do the following steps:

  • echo -n "123nonce=123" | openssl sha256

result: (stdin)= 353f9df92ab1d5e5afe06bb7d1bb42a8ef6654b633d94818007aeafbaf03ca3d

  • echo -n "/0/private/Balance353f9df92ab1d5e5afe06bb7d1bb42a8ef6654b633d94818007aeafbaf03ca3d" | openssl sha512 -hmac $(echo -n "wqtzZWNyZXTCuw==" | base64 -d)

result: (stdin)= 6f19f8f058b0e6dc835692840ccdebc1c415f00d42b75b3d3c21ef5fd43f006e30cc9b51c63aba3268a534bf68978d60d2362bffd31c8125553fb8ec41b2f64d

  • echo -n "6f19f8f058b0e6dc835692840ccdebc1c415f00d42b75b3d3c21ef5fd43f006e30cc9b51c63aba3268a534bf68978d60d2362bffd31c8125553fb8ec41b2f64d" | base64

result:

NmYxOWY4ZjA1OGIwZTZkYzgzNTY5Mjg0MGNjZGViYzFjNDE1ZjAwZDQyYjc1YjNkM2MyMWVmNWZk
NDNmMDA2ZTMwY2M5YjUxYzYzYWJhMzI2OGE1MzRiZjY4OTc4ZDYwZDIzNjJiZmZkMzFjODEyNTU1
M2ZiOGVjNDFiMmY2NGQ=
  • curl -X POST -H "Accept: application/json" -H "API-Key: «key»" -H "API-Sign: NmYxOWY4ZjA1OGIwZTZkYzgzNTY5Mjg0MGNjZGViYzFjNDE1ZjAwZDQyYjc1YjNkM2MyMWVmNWZkNDNmMDA2ZTMwY2M5YjUxYzYzYWJhMzI2OGE1MzRiZjY4OTc4ZDYwZDIzNjJiZmZkMzFjODEyNTU1M2ZiOGVjNDFiMmY2NGQ=" -d "nonce=123" https://api.kraken.com/0/private/Balance

result (assuming valid «key» and «secret»): {"error":["EAPI:Invalid signature"]}

But no matter which permutations I try I keep getting the "Invalid signature" error.

These permutations include but are not limited to:

  • Base64 encoding the API-Sign value (all publicly available Kraken clients do this),
  • uppercasing whatever is to be Base64 encoded,
  • leaving out the '/' in front of the URI path,
  • leaving out the actual nonce number at the front of the SHA256.
  • 1
    you could try to use one of the working api implementations listed, like the python2 one, and add some debug to see where the difference is. – meuh Sep 12 '16 at 16:29
  • Thanks meuh, that made the problem immediately obvious. Kinda silly that I didn't try that before posting my question. – aerique Sep 13 '16 at 9:50
5

Thanks to meuh I figured out the issue. Since I can imagine other people being as silly as me I'll answer my own question:

The problem is that I'm using strings instead of bytes. I don't have the time to figure it out for the command line and cURL (perhaps someone else wants to do that and I'll accept that answer).

For the client I was working on, instead of concatenating /0/private/Balance and the SHA256 hex string 353f9df92ab1d5e5afe06bb7d1bb42a8ef6654b633d94818007aeafbaf03ca3d I should concatenate the bytes for "/0/private/Balance" (47 48 47 112 114 105 118 97 116 101 47 66 97 108 97 110 99 101) and SHA256("123nonce=123") (53 63 157 249 42 177 213 229 175 224 107 183 209 187 66 168 239 102 84 182 51 217 72 24 0 122 234 251 175 3 202 61) (shown as decimal values this time).

Same for the SHA512 HMAC.

Edit:

Since someone asked on Twitter, these are the actual steps to do it on the commandline:

  1. echo -n "/0/private/Balance" > tmp.bin
  2. echo -n "123nonce=123" | openssl sha256 -binary >> tmp.bin
  3. cat tmp.bin | openssl sha512 -binary -hmac $(echo -n "wqtzZWNyZXTCuw==" | base64 -d) | base64 ("wqtzZWNyZXTCuw==" is "«secret»" BASE64 encoded, this should ofcourse be your secret)
  4. curl -X POST -H "Accept: application/json" -H "API-Key: «key»" -H "API-Sign: «output-from-step-3»" -d "nonce=123" https://api.kraken.com/0/private/Balance

As you can seen above, the one thing that was forgotten in the original question was using the -binary switch.

Note: your API key and secret will end up on the commandline (visible with ps aux) and in your shell history!

  • This solution is perfect, but I needed to add a -w 0 after the second base64 to avoid splitting the output in two (without -w, the output is formated in two columns of 76 characters). You also forgot a $ sign before the parenthesis. Final command for line 3: cat tmp.bin | openssl sha512 -binary -hmac $(echo -n "wqtzZWNyZXTCuw==" | base64 -d) | base64 -w 0 – mountrix Jul 22 '17 at 11:12
  • The forgotten $ sign is because I use the fish shell. I should have assumed Bourne shell, sorry. – aerique Jul 23 '17 at 13:30

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.