Как закодировать запрос к API Yobit.net в HMAC_SHA512

183
13 марта 2018, 02:46

Пытаюсь получить данные методом getInfo вот из этого API https://yobit.net/ru/api/

Каждый запрос должен пройти аутентификацию. Аутентификация происходит способом отправки следующих HTTP-заголовков:

Key - API-ключ, пример: FAF816D16FFDFBD1D46EEF5D5B10D8A2

Sign - цифровая подпись, POST-параметры (?param0=val0 & ...& nonce=1) подписанные секретным ключом с помощью HMAC-SHA512

Для Http запроса использую ApacheHttp.

Метод Post - запроса

public static String postApache(String url) {
            String dataFormServer = "";
            String dataToServer="?method=getInfo&nonce=20";
            String key = "xxx";
            String secretKey = "yyy";
            String signedData = calculateHMAC(dataToServer, secretKey);
            try {
                CloseableHttpClient client = HttpClients.createDefault();
                HttpPost httpPost = new HttpPost(url);
                List<NameValuePair> params = new ArrayList<NameValuePair>(2);
                params.add(new BasicNameValuePair("Key", key));
                params.add(new BasicNameValuePair("Sign",signedData));
                httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
                CloseableHttpResponse response = client.execute(httpPost);
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    dataFormServer = org.apache.commons.io.IOUtils.toString(entity.getContent(), "cp1251");
                }
                else System.out.println("Error");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return dataFormServer;
        }

HMAC генератор

private static String calculateHMAC(String data, String key) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), HMAC_SHA512);
        Mac mac = null;
        try {
            mac = Mac.getInstance(HMAC_SHA512);
            mac.init(secretKeySpec);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return toHexString(mac.doFinal(data.getBytes()));
    }
    private static  String toHexString(byte[] bytes) {
        final  char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

Сервер отвечает {"success":0,"error":"invalid key, sign, method or nonce"} Ошибка может быть как в HMAC генераторе, так и в методе postApache. Не уверен ни в том ни в том.

Answer 1

В документации написано, что Key / Sign это заголовки, а вы отправляете их как POST-данные. ?method=getInfo&nonce=20 вот это вы вообще не отправляете нигде. В меня сработал такой код:

public static String postApache(String url) {
    String dataFormServer = "";
    String dataToServer = "method=getInfo&nonce=7";
    String key = "---";
    String secretKey = "---";
    String signedData = calculateHMAC(dataToServer, secretKey);
    try {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Key", key);
        httpPost.addHeader("Sign", signedData);
        httpPost.setEntity(new ByteArrayEntity(dataToServer.getBytes(), ContentType.APPLICATION_FORM_URLENCODED));
        CloseableHttpResponse response = client.execute(httpPost);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            dataFormServer = IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8);
        }
        else System.out.println("Error");
    } catch (IOException e) {
        e.printStackTrace();
    }
    return dataFormServer;
}
private static String calculateHMAC(String data, String key) throws DecoderException {
    SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HMACSHA512");
    Mac mac = null;
    try {
        mac = Mac.getInstance("HMACSHA512");
        mac.init(secretKeySpec);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    }
    byte[] hmac = mac.doFinal(data.getBytes());
    return Hex.encodeHexString(hmac);
}
Answer 2

Решил проблему, может кому пригодится. Использовал бибилотеку commons-codec. Вот рабочий метод кодирования в sha512

private static String calculateHMAC(String data, String key) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), HMAC_SHA512);
        Mac mac = null;
        try {
            mac = Mac.getInstance(HMAC_SHA512);
            mac.init(secretKeySpec);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        try {
            return Hex.encodeHexString(mac.doFinal(data.getBytes("UTF-8")));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

Тут смесь стандартной библиотеки java javax.crypto и апачевской commons-codec. Можно переписать на чистом Apache, получится меньше кода, но не стал заморачиваться.

READ ALSO
Не создается класс в IDEA?

Не создается класс в IDEA?

ЗдравствуйтеУстановил идею и возникла проблема не могу создать класс никакой - выходит сообщение -

121
Как узнать размер объекта (коллекции) в памяти?

Как узнать размер объекта (коллекции) в памяти?

Мне нужно узнать, сколько байт в оперативной памяти занимает определенная коллекция в моем приложении (ArrayList)Нужно это для того, чтобы представлять,...

217
Java. Проблемы с получением текущей даты в ubuntu 17.10

Java. Проблемы с получением текущей даты в ubuntu 17.10

Добрый день! Написал тут программу, которая должна считать кол-во дней до какой-то датыСтолкнулся с тем, что не совсем корректно работают...

135
wait не получает notify на случайной итерации

wait не получает notify на случайной итерации

Задача: Сделать 3 потока, которые будут выполнятся друг за другом, то есть 2-ой поток идет за 1-ым, а 3-ий за вторым, 1-ый за 3-имЗадача должна быть...

141