ok so I have been trying to reproduce the functionality of this PHP script, this may seeem like a long question but if read what I wrote I only need to somehow fix the post_data as the server says that Auth Failed, please check POST Data. Original PHP script (my C code below):
Code:
<?php
function api_query($method, array $req = array()) {
// API settings
$key = ''; // your API-key
$secret = ''; // your Secret-key
$req['method'] = $method;
$mt = explode(' ', microtime());
$req['nonce'] = $mt[1];
// generate the POST data string
$post_data = http_build_query($req, '', '&');
$sign = hash_hmac("sha512", $post_data, $secret);
// generate the extra headers
$headers = array(
'Sign: '.$sign,
'Key: '.$key,
);
// our curl handle (initialize if required)
static $ch = null;
if (is_null($ch)) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Cryptsy API PHP client; '.php_uname('s').'; PHP/'.phpversion().')');
}
curl_setopt($ch, CURLOPT_URL, 'https://www.cryptsy.com/api');
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
// run the query
$res = curl_exec($ch);
if ($res === false) throw new Exception('Could not get reply: '.curl_error($ch));
$dec = json_decode($res, true);
if (!$dec) throw new Exception('Invalid data received, please make sure connection is working and requested API exists');
return $dec;
}
I have (at least I believe I have) taken care of creating the http_build_query call that C does not have just by constructing the query myself. I have the $mt variable in mtStr by using gettimeofday() and I am using the HMAC function from openSSL to sign the post_data with my secret key.
I figured out that the CURLOPT_HTTPHEADER option in C needs a curl_slist linked lists instead of just an array like in PHP, but where I seem to be having problems is in the Post Data. The request will go through but there is an error return saying "check your POST Data". So i went back to the libcurl documentation and found that CURLOPT_POSTFIELDS requires a void* to the data you want to post. So i create void *pData = post_data (where post_data is just a char array, not a pointer so I dont see a probem here) but it still says that it can not valid my identify please check POST data. So if you could take a look at this and tell me where I am going wrong it would be appreciated...
Note that I am not showing my API and secret keys, since I cant change them on my own I would rather not give them out but I know this makes it hard to check my stuff by compiling yourself without a cryptsy account but I'd like to keep it secret for now but there are some dummy keys in there so that there is something to hash that is the proper length etc.
Code:
char *handle_url( char *url )
{
CURL *curl;
struct url_data data;
data.size = 0;
data.data = malloc( 4096 );
if ( NULL == data.data )
{
fprintf( stderr, "failed to allocate memory.\n" );
return NULL;
}
data.data[0] = '\0';
CURLcode res;
// API settings, API key and secret key for your account
char key[] = "9498fbb723961a42816a10bc559cgda7ded2ed8e";
char secret[] = "687cd29def08a7861446c3b4b9c97996c8472e7dd8922da147d3b1343e52e99125d24ace90729fbb";
// method to use against the API, will make changable later
char *method = "mytrades";
// This is required to replace the microtime()/explode methods to
// generate the nonce value required to use the cryptsy API
struct timeval time;
gettimeofday( &time, NULL );
long mt = ( (unsigned long long)time.tv_sec * 1000000 ) + time.tv_usec;
// C is much morer strict than PHP about types so we create a buffer for the
// string representation of the nonce
char mtStr[ 128 ];
sprintf( mtStr, "%lu", mt );
// C does not have a build_http_query as PHP does so
// we just create the string neccessary with strcpy
// and strcat
char post_data[ strlen("method=") + strlen(method) + strlen("&nonce=") + strlen(mtStr) + 1];
strcpy( post_data, "method=" );
strcat( post_data, method );
strcat( post_data, "&" );
strcat( post_data, "nonce=" );
strcat( post_data, mtStr );
printf( "%s", post_data);
printf( "\n");
void *pData = post_data;
//sha512 needs 128 characters
unsigned char *result;
unsigned int len = 128;
result = (unsigned char *)malloc( sizeof(char) * len );
HMAC_CTX ctx;
HMAC_CTX_init( &ctx );
// using sha512
HMAC_Init_ex( &ctx, secret, strlen(secret), EVP_sha512(), NULL );
HMAC_Update( &ctx, (unsigned char *)&post_data, strlen(post_data) );
HMAC_Final( &ctx, result, &len );
HMAC_CTX_cleanup( &ctx );
/*
printf( "\nHMAC digest: " );
for ( int i = 0; i != len; i++ )
{
printf( "%02x", (unsigned int)result[i] );
} */
printf("\n");
// This is the start of setting up the $headers array as in the PHP script
const char *header1 = "Sign: ";
size_t PrefixL = strlen(header1);
char resBuffer[PrefixL + 2 * len + 1];
strcpy( resBuffer, header1);
char *p = &resBuffer[PrefixL];
for ( unsigned int i = 0; i < len; i++ )
{
sprintf( p, "%02x", (unsigned int)result[i]);
p += 2;
}
printf( "%s\n", resBuffer );
const char *header2 = "Key: ";
size_t PrefixR = strlen(header2);
char keyBuffer[PrefixR + 2 * strlen(key) + 1];
strcpy( keyBuffer, header2);
strcat( keyBuffer, key);
printf( "\n%s\n", keyBuffer );
// So now resBuffer is Sign: <128 character sha512 hash here>
// and keyBuffer is Key: <API key here>
free(result);
//struct curl_httppost *chttppostlist = NULL; //a possibility about sending chunked post data not currently used
// originally I set this up so that Sign and Key would be in the array in the same
// manner as the PHP script but libcurl in C needs a curl_slist
const char *headerArray[2];
headerArray[0] = resBuffer;
headerArray[1] = keyBuffer;
// So then we just create a curl_slist and add the resBuffer and keyBuffer (headerArray
// [0] and headerArray[1] respectively) to the curl_slist.
struct curl_slist *cslist= NULL;
curl_slist_append(cslist, headerArray[0]);
curl_slist_append(cslist, headerArray[1]);
curl = curl_easy_init();
if ( curl )
{
curl_easy_setopt( curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible Cryptsy API C Client)");
curl_easy_setopt( curl, CURLOPT_URL, url );
curl_easy_setopt( curl, CURLOPT_POST, 1 ); // is this necessary? isnt in PHP
curl_easy_setopt( curl, CURLOPT_POSTFIELDS, pData ); // <--- something wrong here?
curl_easy_setopt( curl, CURLOPT_HTTPHEADER, cslist );
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_data );
curl_easy_setopt( curl, CURLOPT_WRITEDATA, &data );
curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 0 );
res = curl_easy_perform( curl );
if ( res != CURLE_OK )
{
fprintf( stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
curl_slist_free_all( cslist );
curl_easy_cleanup( curl );
}
return data.data;
}