Search code examples
c#php.netwinformsweb-to-winforms

PHP to .NET (winform) API integration cause some problems


I am trying to implement the last version of Bittrex api to a small tool I'm doing for myself, I've got most things okay except that they inquire this for the V1.1 :

    For this version, we use a standard HMAC-SHA512 signing. Append apikey and nonce to your request and calculate the HMAC hash and include it under an apisign header. Note: the nonce is not respected right now but will be enforced later.

$apikey='xxx';
$apisecret='xxx';
$nonce=time();
$uri='https://bittrex.com/api/v1.1/market/getopenorders?apikey='.$apikey.'&nonce='.$nonce;
$sign=hash_hmac('sha512',$uri,$apisecret);
$ch = curl_init($uri);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('apisign:'.$sign));
$execResult = curl_exec($ch);
$obj = json_decode($execResult);

To implement it, I did this :

// TODO : add a way to get this from the user
var apiKey = ApiKey;
var apiSecret = ApiSecret;

// var nonce = (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; // same as time() in PHP
var encoding = Encoding.UTF8;
var url = @"https://bittrex.com/api/v1.1/account/getbalances?apikey=" + apiKey;
var result = Gethmacsha512(encoding, apiSecret, url);

// some var for the request
var account = new List<AccountCurrencies>();

// sending it to get the response
var request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("apisign:",result);
request.ContentType = "application/json";
var response = (HttpWebResponse)request.GetResponse();
var stream = response.GetResponseStream();

Resp.GetValue(stream, account);
return account;

Which returns me that the HTTPHEADER isn't good.

As you see, I used the solutions I found on this website (Gethmacsha512, the way to get the time from php to .Net, some other tips & tricks) but I just can't get the way I'm supposed to send apisign over....

If any of you could direct me toward a solution, or indicate me what I am searching for (as I don't know what curl is), or even whip me up a bit of example code that I could study to understand that part, that would be awesome.

EDIT :

I have updated the above as follow :

// TODO : add a way to get this from the user
var apiKey = ApiKey;
var apiSecret = ApiSecret;

var nonce = (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; // same as time() in PHP
var encoding = Encoding.UTF8;
var url = @"https://bittrex.com/api/v1.1/account/getbalances?apikey=" + apiKey;
            var urlForAuth = url + "&nonce=" + nonce;
            var result = Gethmacsha512(encoding, apiSecret, urlForAuth);

// some var for the request
var account = new List<AccountCurrencies>();

// sending it to get the response
var request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("apisign",result);
request.Headers.Add("nonce", nonce.ToString());
request.ContentType = "application/json";
var response = (HttpWebResponse)request.GetResponse();
var stream = response.GetResponseStream();

Resp.GetValue(stream, account);
return account;

The culprit to the problem above was the "apisign:" as the ':' was an illegal character, and I tried to integrate the "nonce" because while everything compiles, the authentication fail due to "nonce" not being submited. So I tried to add it in the URL, or in the header, but both fails.


Solution

  • So the solution was actually "rather" simple. In case anyone is doing something with Bittrex API too, here is the code that works :

    public static List<AccountCurrencies> GetAccountCurrencies()
        {
            if (Settings.Default.APIKey == null || Settings.Default.APISecret == null) return new List<AccountCurrencies>();
            var nonce = (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; // same as time() in PHP, need to integrate it
            var encoding = Encoding.UTF8;
            var urlForAuth = @"https://bittrex.com/api/v1.1/account/getbalances?apikey=" + Settings.Default.APIKey + "&nonce=" + nonce;
            var result = Gethmacsha512(encoding, Settings.Default.APISecret, urlForAuth);
    
        // some var for the request
        var account = new List<AccountCurrencies>();
    
        // sending it to get the response
        var request = (HttpWebRequest)WebRequest.Create(urlForAuth);
        request.Headers.Add("apisign",result);
        //request.Headers.Add("nonce", nonce.ToString());
        request.ContentType = "application/json";
        var response = (HttpWebResponse)request.GetResponse();
        var stream = response.GetResponseStream();
    
        Resp.GetValue(stream, account);
        return account;
    }
    
    
    private static string Gethmacsha512(Encoding encoding, string apiSecret, string url)
    {
        // doing the encoding
        var keyByte = encoding.GetBytes(apiSecret);
        string result;
        using (var hmacsha512 = new HMACSHA512(keyByte))
        {
            hmacsha512.ComputeHash(encoding.GetBytes(url));
    
            result = ByteToString(hmacsha512.Hash);
        }
        return result;
    }
    
    static string ByteToString(IEnumerable<byte> buff)
    {
        return buff.Aggregate("", (current, t) => current + t.ToString("X2"));
    }