-2

The authentication process in the Bitfinex API is:

Say the client wants to make a request to

POST https://api.bitfinex.com/v1/order/new

with a payload of

{
"request": "/v1/order/new",
"nonce": "1234",
"option1": ...
} 

The nonce provided must be strictly increasing.

To authenticate a request, use the following:

payload = parameters-dictionary -> JSON encode -> base64
signature = HMAC-SHA384(payload, api-secret) as hexadecimal
send (api-key, payload, signature) 

These are encoded as HTTP headers named:

X-BFX-APIKEY
X-BFX-PAYLOAD
X-BFX-SIGNATURE 

Full documentation in https://www.bitfinex.com/pages/api

I want to build a robot, so I researched around and I wrote this code (whith help):

#include<openssl/pem.h>

/* A BASE-64 ENCODER USING OPENSSL (by Len Schulwitz)
 * Parameter 1: A pointer to the data you want to base-64 encode.
 * Parameter 2: The number of bytes you want encoded.
 * Return: A character pointer to the base-64 encoded data (null-terminated for string output).
 * On linux, compile with "gcc base64_encode.c -o b64enc -lcrypto" and run with "./b64enc".
 * This software has no warranty and is provided "AS IS".  Use at your own risk.
 * Published at http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
 */

/*This function will Base-64 encode your data.*/
char * base64encode (const void *b64_encode_me, int encode_this_many_bytes){
    BIO *b64_bio, *mem_bio;   //Declare two BIOs.  One base64 encodes, the other stores     memory.
    BUF_MEM *mem_bio_mem_ptr; //Pointer to the "memory BIO" structure holding the base64 data.

    b64_bio = BIO_new(BIO_f_base64());  //Initialize our base64 filter BIO.
    mem_bio = BIO_new(BIO_s_mem());  //Initialize our memory sink BIO.
    BIO_push(b64_bio, mem_bio);  //Link the BIOs (i.e. create a filter-sink BIO chain.)
    BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL);  //Don't add a newline every 64 characters.

    BIO_write(b64_bio, b64_encode_me, encode_this_many_bytes); //Encode and write our b64 data.
    BIO_flush(b64_bio);  //Flush data.  Necessary for b64 encoding, because of pad characters.

    BIO_get_mem_ptr(mem_bio, &mem_bio_mem_ptr);  //Store address of mem_bio's memory structure.
    BIO_set_close(mem_bio,BIO_NOCLOSE); //Permit access to mem_ptr after BIOs are destroyed.
    BIO_free_all(b64_bio);  //Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).

    (*mem_bio_mem_ptr).data[(*mem_bio_mem_ptr).length] = '\0';  //Adds a null-terminator.

    return (*mem_bio_mem_ptr).data; //Returns base-64 encoded data. (See: "buf_mem_st" struct).
}

#include<stdio.h>
#include<curl/curl.h>
#include<string.h>
#include<malloc.h>
#include<openssl/hmac.h>

int main(){

char key[]="X-BFX-APIKEY:xxxx";
char secret[]="xxxx";

//preparation of X-BFX-PAYLOAD header
char data[]="{\"request\":\"/v1/orders\",\"nonce\":\"46\"}";
char pre_data[]="X-BFX-PAYLOAD:";
int bytes_to_encode=sizeof(data)-1; 
char *data_encoded=base64encode(data,bytes_to_encode);
char *payload;
payload=(char *)malloc(strlen(data_encoded)*sizeof(char)+strlen(pre_data)*sizeof(char));
*payload='\0';
strcat(payload,pre_data);
strcat(payload,data_encoded);

//variables related to hmac
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
unsigned int len=128;
unsigned char *mac;
mac=(unsigned char *)malloc(sizeof(char)*len);
//using sha384
HMAC_Init_ex(&ctx,secret,strlen(secret),EVP_sha384(),NULL);
HMAC_Update(&ctx,(unsigned char *)&data_encoded,strlen(data_encoded));
HMAC_Final(&ctx,mac,&len);

//preparation of X-BFX-SIGNATURE header
int i;
const char *pre_sign="X-BFX-SIGNATURE:";
size_t pre_sign_len=strlen(pre_sign);
char sign[pre_sign_len+2*len+1];
strcpy(sign,pre_sign);
char *p=&sign[pre_sign_len];
//mac to hex
for(i=0;i<len;i++){
   sprintf(p,"%02x",(unsigned int)mac[i]);
   p+=2;  
}

//variables related to CURL
CURL *request;
FILE *answer=fopen("answer.dat","w");
CURLcode control;
struct curl_slist *headers=NULL;
//CURL preparation
curl_global_init(CURL_GLOBAL_SSL);
request=curl_easy_init();
curl_easy_setopt(request,CURLOPT_WRITEDATA,(void *)answer);
curl_easy_setopt(request,CURLOPT_URL,"https://api.bitfinex.com/v1/orders");
curl_easy_setopt(request,CURLOPT_TIMEOUT,10);
curl_easy_setopt(request,CURLOPT_POST,1L); 
headers=curl_slist_append(headers,key);
headers=curl_slist_append(headers,payload);
headers=curl_slist_append(headers,sign);
curl_easy_setopt(request,CURLOPT_HTTPHEADER,headers);
curl_easy_setopt(request,CURLOPT_POSTFIELDS,"");
curl_easy_setopt(request, CURLOPT_SSL_VERIFYPEER,0L);

//do
if((control=curl_easy_perform(request))!=CURLE_OK)printf("curl error %d\n",(int)control);

//clean up...
return 0;
}

But always when I send the request I receive the answer:

{"message":"Invalid X-BFX-SIGNATURE."}

Since that the responses from APIs are not always precise I am not sure exactly what is wrong so I tried to change a lot of things like the string data format and the hmac process, but no result. Probably the problem is not in the hmac process which is working nicely for other API but now I cant figure out what is wrong.

Out of desperation I'm turning here, does anyone know why it is not working?

thanks in advance

Rafael
  • 43
  • 4
  • "I wrote this code" - that code has a direct reference to http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c and is written by @schulwitz as this answer: http://stackoverflow.com/a/16511093/541688. I have a feeling that you are lying. – Oleg Estekhin Jul 17 '14 at 06:31
  • Sorry, I did not wrote the entire code. Still there other parts I basically learned from someone and I rewrote, I could give more references. The only think I did alone was the CURL part. Is there any problem? – Rafael Jul 17 '14 at 16:10

1 Answers1

0

Solved, I tried an online hash encryption and it worked, the problem was in the hmac process but what is wrong is another question.

Rafael
  • 43
  • 4