Kraken API:身份验证问题(无效密钥)

use*_*232 11 java authentication api

我正在尝试在Java中实现比特币交换Kraken的API.不幸的是,我一直试图执行身份验证以检索私有用户数据.

特别是,我正在玩以下实现: http ://pastebin.com/nHJDAbH8 Kraken API的文档在这里:https://www.kraken.com/help/api

但是,到目前为止我只收到了{"error":["EAPI:Invalid key"]}.我在实现中找不到任何错误,我尝试了几种不同的API密钥.有人可能会快速查看实现并查找代码中的缺陷吗?或者有人成功实施了Kraken API?

非常感谢!

身份验证说明如下:

HTTP-Header:API-Key = API密钥API-Sign =使用HMAC-SHA512(URI路径+ SHA256(nonce + POST数据))和base64解码的秘密API密钥的消息签名

发布数据:nonce =总是增加无符号64位整数otp =双因子密码(如果启用了双因子,否则不需要)注意:在我的情况下,otp被禁用,因此后期数据仅包含随机数.

我正在尝试的实现是:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Cfr*_*Cfr 6

以下是我如何使用 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
Run Code Online (Sandbox Code Playgroud)

所以你需要:

  • 获取 的 SHA256 哈希值nonce + body,即SHA256("1487687774151000nonce=1487687774151000")
  • 将摘要的原始字节附加到path(结果将是不可打印的,平衡方法的示例路径是"/0/private/Balance"),
  • 使用 base64-decoded 获取 HMAC SHA512 摘要secret
  • 编码为 Base64。


Jas*_*iti -4

删除路径变量的“/”前缀。

String path = version + "/private/" + method; // The path like "0/private/Balance"
Run Code Online (Sandbox Code Playgroud)