Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kraken API: Problems with authentication (Invalid key)

I am trying to implement the API of the bitcoin exchange Kraken in Java. Unfortunately I got stuck at trying to execute an authentication in order to retrieve private user data.

In particular, I was playing with the following Implementation: http://pastebin.com/nHJDAbH8 The documentation of Kraken's API is here: https://www.kraken.com/help/api

However, so far I only received {"error":["EAPI:Invalid key"]} . I couldn't find any mistake in the implementation and I tried several different API-keys. Could someone maybe have a quick look at the implementation and look for flaws in the code? Or has someone successfully implemented the Kraken API?

Many thanks!

The instructions for authentication are:

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

Post data: nonce = always increasing unsigned 64 bit integer otp = two-factor password (if two-factor enabled, otherwise not required) Note: in my case otp is disabled, so post-data consists only of nonce.

The implementation I was experimenting with is:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class KrakenClient {

    protected static String key = "myAPIKey";     // API key
    protected static String secret = "MySecret====";  // API secret
    protected static String url = "api.kraken.com";     // API base URL
    protected static String version = "0"; // API version


    public static void main(String[] args) throws Exception {
        queryPrivateMethod("Balance");
    }

    public static void queryPrivateMethod(String method) throws NoSuchAlgorithmException, IOException{

        long nonce = System.currentTimeMillis();

        String path = "/" + version + "/private/" + method; // The path like "/0/private/Balance"

        String urlComp = "https://"+url+path; // The complete url like "https://api.kraken.com/0/private/Balance"

        String postdata = "nonce="+nonce;

        String sign = createSignature(nonce, path, postdata);

        postConnection(urlComp, sign, postdata);
    }

    /**
     * @param nonce
     * @param path
     * @param postdata
     * @return
     * @throws NoSuchAlgorithmException
     * @throws IOException
     */
    private static String createSignature(long nonce, String path,
            String postdata) throws NoSuchAlgorithmException, IOException {

        return hmac(path+sha256(nonce + postdata),  new String(Base64.decodeBase64(secret)));
    }

    public static String sha256Hex(String text) throws NoSuchAlgorithmException, IOException{
        return org.apache.commons.codec.digest.DigestUtils.sha256Hex(text);
    }

    public static byte[] sha256(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException{
        MessageDigest md = MessageDigest.getInstance("SHA-256");

        md.update(text.getBytes());
        byte[] digest = md.digest();

        return digest;
    }

    public static void postConnection(String url1, String sign, String postData) throws IOException{

        URL url = new URL( url1 );
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        connection.addRequestProperty("API-Key", key);
        connection.addRequestProperty("API-Sign", Base64.encodeBase64String(sign.getBytes()));
        //      connection.addRequestProperty("API-Sign", sign);
        connection.addRequestProperty("User-Agent", "Mozilla/4.0");
        connection.setRequestMethod( "POST" );
        connection.setDoInput( true );
        connection.setDoOutput( true );
        connection.setUseCaches( false );
        //      connection.setRequestProperty( "Content-Type",
        //              "application/x-www-form-urlencoded" );
        connection.setRequestProperty( "Content-Length", String.valueOf(postData.length()) );

        OutputStreamWriter writer = new OutputStreamWriter( connection.getOutputStream() );
        writer.write( postData );
        writer.flush();


        BufferedReader reader = new BufferedReader(
                new InputStreamReader(connection.getInputStream()) );

        for ( String line; (line = reader.readLine()) != null; )
        {
            System.out.println( line );
        }

        writer.close();
        reader.close();
    }


    public static String hmac(String text, String secret){

        Mac mac =null;
        SecretKeySpec key = null;

        // Create a new secret key
        try {
            key = new SecretKeySpec( secret.getBytes( "UTF-8"), "HmacSHA512" );
        } catch( UnsupportedEncodingException uee) {
            System.err.println( "Unsupported encoding exception: " + uee.toString());
            return null;
        }
        // Create a new mac
        try {
            mac = Mac.getInstance( "HmacSHA512" );
        } catch( NoSuchAlgorithmException nsae) {
            System.err.println( "No such algorithm exception: " + nsae.toString());
            return null;
        }

        // Init mac with key.
        try {
            mac.init( key);
        } catch( InvalidKeyException ike) {
            System.err.println( "Invalid key exception: " + ike.toString());
            return null;
        }


        // Encode the text with the secret
        try {

            return new String( mac.doFinal(text.getBytes( "UTF-8")));
        } catch( UnsupportedEncodingException uee) {
            System.err.println( "Unsupported encoding exception: " + uee.toString());
            return null;
        }
    }
}
like image 232
user3116232 Avatar asked Oct 13 '14 19:10

user3116232


People also ask

How do I get my Kraken App API key?

Creating an API KeySign in to your Kraken account. Click on your name in the upper-right corner of the page. Click on Security and then API. Click on the Add key button.

How do I update Kraken API permissions?

Steps on how to add permissions for the staking API:Click on your name in the upper-right corner of the page. Navigate to Security and then select API. Click Add key. Add the desired key permissions by selecting the key permissions corresponding to the desired functionality of the staking API.

What is Kraken API key?

You can change API permissions at any time from your Kraken account settings; there's no need to create a new key. The API key is like a username, and the API private key is like the password. The combination of the two can be displayed as a QR code which can be scanned instead of having to manually enter the keys.


Video Answer


1 Answers

Here is how I've got it working with Haskell:

signature body nonce path secret = convertToBase Base64 hmacsha512
  where
    sha256 = convert (hash $ nonce `append` body :: Digest SHA256)
    hmacsha512 = hmac secretd (path `append` sha256) :: HMAC SHA512
    secretd = fromRight $ convertFromBase Base64 secret :: ByteString

So you need to:

  • get SHA256 hash of nonce + body, i.e. SHA256("1487687774151000nonce=1487687774151000")
  • append raw bytes of digest to path (result would be unprintable, example path for balance method is "/0/private/Balance"),
  • get HMAC SHA512 digest using base64-decoded secret,
  • encode to Base64.
like image 68
Cfr Avatar answered Sep 28 '22 10:09

Cfr