# API Aufruf mit GET Request und HMAC



## java666 (26. Okt 2017)

Hallo,

ich versuche gerade einen API-Client zu programmieren. Das erste Java-Programm seit ca. 8 Jahren.
Eigentlich ist das ganze gar nicht so wirklich schwer, aber leider bin ich jetzt an einem Punkt wo meine Java Kenntnisse am ende sind.
Das Problem ist das ich einen GET-Request an die API schicke, ohne einen GET Body.
Jetzt kann man aber leider den HMAC(SHA256) Hash nicht richtig erstellen weil man dazu ja einen SecretKey benötigt, dieser SecretKey kann aber leider nicht bei einem GET-Request mit übermittelt werden, zumindest nicht in Java(oder besser gesagt, ich nicht).
In PHP kann man die HASH_HMAC einfach ohne ein Secret-Key aufrufen und der Hmac Hash wird trotzdem erstellt. Auch könnte ich in PHP per cUrl einfache einen Customheader für GET erstellen und somit auch den Secret-Key an die API senden.
Hier mal der Code der für den API Aufruf zuständig ist.

```
private String apiCall( String domain, String publicHash, String privateHash ) {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet(domain);
        String secret = "[]";
        httpget.addHeader("Accept", "application/json");
        httpget.addHeader("Content-Type", "application/json");
        httpget.addHeader("Public", publicHash);
        ApiSecurity privateKey = new ApiSecurity();
        privateKey.setPrivateKey(privateHash, secret);
        //System.out.println(privateKey.getPrivateKey());
        httpget.addHeader("Hash", privateKey.getPrivateKey());
        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpget);
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
        BufferedReader rd = null;
        try {
            rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        } catch (UnsupportedOperationException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        StringBuffer result = new StringBuffer();
        String line = "";
        try {
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
        return result.toString();
    }
```

Hier noch der Code der zuständig ist für die Erstellung des Hmac-Hash

```
package API_Client;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

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


public class ApiSecurity {
   
    String privateKey = null;

    public void setPrivateKey( String key, String secret) {
        Mac hashHmac = null;
        String algorythmus = "HmacSHA256";
        try {
            hashHmac = Mac.getInstance(algorythmus);
            SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), algorythmus);
            try {
                hashHmac.init(secretKey);
                this.toHexString(hashHmac, key);
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
    }
   
    public String getPrivateKey() {
        return privateKey;
    }
   
    private void toHexString( Mac hashObj, String key ) {
        String temp = "";
        byte[] digest = hashObj.doFinal(key.getBytes());
        for (byte b : digest) {
            temp += String.format("%02x", b);
        }
       
        privateKey = temp;
       
    }
   
}
```
Wenn ich den Hmac-Hash in PHP erstellen lasse und in dann in der Methode hinterlege liefert die API auch schon die Daten.
Vllt habt ihr ja eine Idee was ich machen könnte damit der Key ohne Secret-Key erstellt wird oder ich den Secret-Key auch bei einem GET-Request mitsenden kann.

Ich hoffe das Problem ist ersichtlich und genau beschrieben.

Vielen dank jetzt schon einmal für eure Hilfe und Zeit dir ihr euch nehmt.


----------



## mrBrown (27. Okt 2017)

java666 hat gesagt.:


> Auch könnte ich in PHP per cUrl einfache einen Customheader für GET erstellen und somit auch den Secret-Key an die API senden.





java666 hat gesagt.:


> Vllt habt ihr ja eine Idee was ich machen könnte damit der Key ohne Secret-Key erstellt wird oder ich den Secret-Key auch bei einem GET-Request mitsenden kann.


Füg doch mit `addHeader` den benötigten Header hinzu?


----------



## java666 (27. Okt 2017)

Ich habe es schon einmal mit dem addHeader versucht. Leider ohne erfolg. 
Jetzt hab ich aber tatsächlich heute in der früh zumindest eine Teillösung für das Problem gefunden.

```
private String apiCall( String domain, String publicHash, String privateHash ) {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpget = new HttpPost(domain);
        String secret = "[]";
        httpget.addHeader("Accept", "application/json");
        httpget.addHeader("Content-Type", "application/json");
        httpget.addHeader("Public", publicHash);
        ApiSecurity privateKey = new ApiSecurity();
        System.out.println( privateHash );       
        privateKey.setPrivateKey(privateHash, secret);
        System.out.println(privateKey.getPrivateKey());
        httpget.addHeader("Hash", privateKey.getPrivateKey());
        StringEntity xmlEntity = null;
        try {
            xmlEntity = new StringEntity(secret);
        } catch (UnsupportedEncodingException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
        httpget.setEntity(xmlEntity);
        httpget.addHeader("X-HTTP-Method-Override", "GET");
        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpget);
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
        BufferedReader rd = null;
        try {
            rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        } catch (UnsupportedOperationException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        StringBuffer result = new StringBuffer();
        String line = "";
        try {
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
        return result.toString();
    }
```

Ich sende jetzt einen POST-Request der ja einen Body haben kann. Und überschreibe dann den POST-Header mit:
httpget.addHeader("X-HTTP-Method-Override", "GET");
Jetzt kommt an der API zwar eigentlich ein POST an aber dank diesem Header wird dann die GET Methode verwendet.
Jetzt habe ich aber immer noch ein Problem mit dem Hash-Wert.
Ich bekomme verschiedene Hash-Werte geliefert:
Key: gQNHOfl0tlKRA8vuTnxzyDlX8TMITafUqiHin9l7kyW18UpG7q5Intds
PHP: e79cfd621c5db54b5c88e85cd8ab3609b303a3db120f6d12f8523b4fde12f3f4
Java: aeee73f07e696ee524b9c8292b2062d60a322e9414a107f9da8ce0ede1e01ebc

PHP Code zum erstellen

```
$data = json_encode(
    array()
);

$privateHash = 'gQNHOfl0tlKRA8vuTnxzyDlX8TMITafUqiHin9l7kyW18UpG7q5Intds';
echo hash_hmac('sha256', $data, $privateHash);
```


```
public void setPrivateKey( [URL='http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string']String[/URL] key, [URL='http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string']String[/URL] secret) {
        Mac hashHmac = null;
        [URL='http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string']String[/URL] algorythmus = "HmacSHA256";
        try {
            hashHmac = Mac.getInstance(algorythmus);
            SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), algorythmus);
            try {
                hashHmac.init(secretKey);
                this.toHexString(hashHmac, key);
            } catch ([URL='http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+invalidkeyexception']InvalidKeyException[/URL] e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } catch ([URL='http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+nosuchalgorithmexception']NoSuchAlgorithmException[/URL] e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
    }
```

Vielleicht hat hierfür noch jemand eine Idee?


----------



## java666 (27. Okt 2017)

Hallo,

ich habe es jetzt geschafft das ein Hmac Hash erstellt wird. 

```
String secret = "[]";
wurde zu
String secret = privateHash;
```
Mit dieser Änderung geht es jetzt. Allerdings kann ich nicht sagen warum. Vllt hat ja dafür noch jemand eine Erklärung?


----------

