2017-09-18 1 views
0

내 GDAX 평형을 얻으려고하고 있지만 Java에서 올바르게 인코딩/디코딩을 처리 할 수 ​​없다고 생각합니다. API 참조는 여기에 있습니다 : https://docs.gdax.com/#authentication이고 내가하려는 부분은 계정 -> 계정 목록 (위의 링크에서 조금 아래로 스크롤해야 함) 아래에 있습니다.Java에서 Base64 및 HMAC SHA-256 인코딩/디코딩

여기에 제가 가지고있는 코드가 있습니다. 나는 구글과 여기에서 얼마나 많은 검색을 했음에도 불구하고 제대로 작동하지 않는 것 같다. "잘못된 요청 - 잘못된 요청 형식"을 의미하는 서버에서 400 오류가 계속 발생합니다.

// Decode the secret key 
    byte[] decodedSecret; 
    try 
    { 
     decodedSecret = Base64.decode(SECRET_KEY); 
    } 
    catch (Base64DecodingException ex) 
    { 
     System.out.println("Failed to decode secret key."); 
     return null; 
    } 

    // Make the header parameters 
    long timestamp = (new GregorianCalendar()).getTimeInMillis()/1000; 
    String preSign = "" + timestamp + "GET" + BASE_URL + "/accounts"; 

    byte[] encodedhash; 
    try 
    { 
     Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); 
     try 
     { 
      sha256_HMAC.init(new SecretKeySpec(decodedSecret, "HmacSHA256")); 
     } 
     catch (InvalidKeyException ex) 
     { 
      System.out.println("Failed due to invalid key exception."); 
      System.out.println(ex.getMessage()); 
      return null; 
     } 
     encodedhash = sha256_HMAC.doFinal(preSign.getBytes()); 
    } 
    catch (NoSuchAlgorithmException ex) 
    { 
     System.out.println("Failed to make SHA-256 encode because of no such algorithm."); 
     return null; 
    } 

    HashMap<String, String> parameters = new HashMap<>(); 
    parameters.put("CB-ACCESS-KEY", API_KEY); 
    parameters.put("CB-ACCESS-SIGN", Base64.encode(encodedhash)); 
    parameters.put("CB-ACCESS-TIMESTAMP", "" + timestamp); 
    parameters.put("CB-ACCESS-PASSPHRASE", PASSPHRASE); 

    // Send the request 
    String response = sendGet(BASE_URL + "/accounts", parameters); 

다음은 문제가있는 경우를 대비하여 sendGet() 내부 코드입니다. 매개 변수없이 작동하는지는 알지만 작동하도록 설정할 수 없기 때문에 매개 변수를 제대로 사용하는지 여부는 알 수 없습니다.

// Set up the connection 
    URL url = null; 
    try 
    { 
     url = new URL(urlStr); 
    } 
    catch (MalformedURLException ex) 
    { 
     return null; 
    } 
    HttpURLConnection con; 
    try 
    { 
     con = (HttpURLConnection) url.openConnection(); 
    } 
    catch (IOException ex) 
    { 
     System.out.println("Returning null because of failure to open connection."); 
     return null; 
    } 
    try 
    { 
     con.setRequestMethod("GET"); 
    } 
    catch (ProtocolException ex) {} 
    if (parameters != null) // if there are parameters to add to the connection 
    { 
     for (Map.Entry<String, String> pair : parameters.entrySet()) // for each pair in parameters 
     { 
      try 
      { 
       con.addRequestProperty(pair.getKey(), pair.getValue()); 
      } 
      catch (Exception ex) 
      { 
       System.out.println("Failed to add " + pair.getKey() + "."); 
      } 
     } 
    } 

    // Get the response 
    int responseCode; 
    try 
    { 
     responseCode = con.getResponseCode(); 

     BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); 
     StringBuilder responseBldr = new StringBuilder(); 
     String line; 
     while ((line = in.readLine()) != null) // while we have read another line 
     { 
      responseBldr.append(line); 
     } 
     in.close(); 
     return responseBldr.toString(); 
    } 
    catch (IOException ex) 
    { 
     System.out.println("Returning null from network IOException."); 
     System.out.println(ex.getMessage()); 
     return null; 
    } 
+0

Content-type 헤더를 설정 했습니까? – algrid

+0

나는 그것을 설정하지 않았다. 고마워요. 그래도 나는 여전히 400을 받는다. 이것이 내가 content-type을 추가 한 것입니다 : con.addRequestProperty ("Content-type", contentType); – cmasupra

+0

또한'preSign'은 아마도'BASE_URL'을 포함해서는 안됩니다. – algrid

답변

0

로컬로 작업하고 있습니다. 서명을 이중으로 인코딩 한 것 같습니다.

서명을 만드는 단계

는 다음과 같습니다

  1. 가의 KeySpec를 얻기 위해 비밀을 해독
  2. 서명의 기초를 형성 초기 문자열을 만듭니다 (새 SecretKeySpec의()) 초기화
  3. 당신의
  4. 요청 서명을 인코딩하기 위해 비밀을 사용 keySpec에 함께 HMAC (()는 sha256Hmac.init) (sha256Hmac.doFinal는())
  5. 베이스 64이 단계의 결과를 부호화 4.

위의 스 니펫에서 작성한 유일한 오류는 헤더에서 다시 base64로 인코딩하는 것입니다.

HTH