Android Question Connecting securely with HttpUtils2?

cyiwin

Active Member
Licensed User
Longtime User
I want to make an app that can place trades on cryptsy.com and I'm hoping for some general guidance. The API website https://www.cryptsy.com/pages/api seems to be inclusive in stating what it needs. I was able to stumble around with example php program at the bottom of the page and got it to work, but I want to do that with B4A!

I am trying to use the HttpUtils2 library. I am using my API key with the Username method and private key with the Password method. I'm using PostString to call the API website and give my credentials. I believe it is the cryptsy website that returns this to my logs:

{"success":"0","error":"Unable to Authorize Request - Check Your Post Data"}

I am new to HttpUtils2 but I think my hang up is my private "sign" key. From the link I posted:

Sign — ALL POST data (param=val&param1=val1) signed by a secret key according to HMAC-SHA512 method. Your secret key and public keys can be generated from your account settings page.

An additional security element must be passed into the post:

nonce - All requests must also include a special nonce POST parameter with incrementing integer. The integer must always be greater than the previous requests nonce value.
Does this mean I have send my signed key in an encrypted format? Is there a way to send a nonce POST?

Also, I have done a lot of googling but if someone could suggest a website that teaches a complete beginner what is going on when a PostString calls a website that would also be awesome.

Thanks
 

DonManfred

Expert
Licensed User
Longtime User
Look at the php example on site https://www.cryptsy.com/pages/api
You have to sha1-encrypt your postdata.

PHP:
$sign = hash_hmac("sha512", $post_data, $secret);

The result of signing must be transmitted in sign-Key on postrequest

I´m not famailar with this api; just have read the docu
 
Upvote 0

cyiwin

Active Member
Licensed User
Longtime User
Thanks for your reply! So I do need to encrypt the post request. Is that something B4A can do?...Or will I have to use B4A to communicate through php somehow?
 
Upvote 0

cyiwin

Active Member
Licensed User
Longtime User
err... I hit a snag. The php line of code
PHP:
$sign = hash_hmac("sha512", $post_data, $secret);
looks like it wants to convert two variables to sha-512. $post_data = "method=getinfo&nonce=1393376255", (nonce is an ever increasing integer measuring time). $Secret is my private API key.

Looking up the php "hash_hmac" function it states: stringhash_hmac ( string $algo , string $data , string $key ). This makes sense to me but I can't find a B4A equivalent.

In the Encryption library it looks like MessageDigest is the only part that supports SHA-512? I found some helpful code in the forums for MessageDigest but it only allows one variable.

GetMessageDigest (data() As Byte, algorithm As String) As Byte()

It seems to allow the data and algorithm but not the key part. I tried messing around with KeyPairGenerator and Signature from the Encryption library but they didn't accept sha-512 as an algorithm. Am I looking in the wrong part of the library?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Try this:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim sign() As Byte = HashHmac("data", "secret")
End Sub

Sub HashHmac(data As String, secret As String) As Byte()
   Dim m As Mac
   Dim kg As KeyGenerator
   kg.Initialize("HmacSHA512")
   kg.KeyFromBytes(secret.GetBytes("UTF8"))
   m.Initialise("HmacSHA512", kg.Key)
   m.Update(data.GetBytes("UTF8"))
   Return m.Sign
End Sub
 
Upvote 0

cyiwin

Active Member
Licensed User
Longtime User
Thanks for the code, it really is nice of you to write it. I am new to encryption, but from the php output of $sign it looks like I need to convert the returned array of bytes to a string of hexadecimals before submitting it to cryptsy? After a lot of studying your code, it appears your subroutine returns an array of 64 bytes, each value ranging from -128 to 127.

Using your code, the Encryption library and the ByteConverter library, this is what I have so far:

B4X:
Sub Process_Globals
   
End Sub

Sub Globals
    Dim API_Key, API_Secret, Post_Data As String
    Dim Byte_Conv As ByteConverter
    Dim stringdata As String 
End Sub

Sub Activity_Create(FirstTime As Boolean)
    API_Secret = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    Post_Data = "method=getinfo&nonce=1"
   
    Dim Sign() As Byte = HashHmac(Post_Data, API_Secret)
    Dim Sign_String As String
    Sign_String = Byte_Conv.StringFromBytes(Sign, "UTF8")
   
    Log("Sign_String = " & Sign_String)
   
End Sub

Sub HashHmac(data As String, secret As String) As Byte()
    Dim m As Mac                                            'm As Message Authentication Code
    Dim kg As KeyGenerator                                 
    kg.Initialize("HmacSHA512")                             'initialize kg using HmacSHA512 algorithm
    kg.KeyFromBytes(secret.GetBytes("UTF8"))                'encode string "secret" to an array of Bytes using UTF8
    m.Initialise("HmacSHA512", kg.Key)                      'initialize m using HmacSHA512 algorithm and the secret key
    m.Update(data.GetBytes("UTF8"))                         'encodes post data to an array of Bytes and loads it to be signed 
    Return m.Sign                                           'sign the loaded data using the secret key, return the calc signature data
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Log Output:
Sign_String = �D�l� @�ת'���t����Ο�eRh��W�X�z��\��5�8�E I{�3�=,�fy

Using the real API_Secret gets me similar results.

The array of bytes from "Sign()" vary from -128 to 127. When converting to a string, the positive bytes get characters and the negative bytes get diamonds. From my experimenting with UTF8 it looks like the numbers "0,1,2,3,4,5,6,7,8,9" are from byte values 48 to 57 and letters "a,b,c,d,e,f" are from byte values 65 to 71. Does this mean my output array of bytes "Sign()" needs to be in those ranges to get a real hexadecimal output?

Am I on the right track by trying to convert to a string, or did I fly way off the rails?
 
Upvote 0

cyiwin

Active Member
Licensed User
Longtime User
Does it work with your API with this change now?

Yes, the 128 Hex "Sign" that Erel's code generates matches the 128 Hex "Sign" that the php generates! Really nice!

Now I just have to figure out how to send it to cryptsy. I'm trying to translate phps CURLOPT_POSTFIELDS and CURLOPT_HTTPHEADER to B4A's HttpUtils2. If I get it all working I'll post the program, it seems like this could be useful to someone else...
 
Upvote 0

cyiwin

Active Member
Licensed User
Longtime User
If you don't want to read all of this, my main question is how do you send variables into a request header?


I'm stuck yet again, this time with HttpUtils2. I'm trying to convert the PHP at the bottom of this website https://www.cryptsy.com/pages/api.

Everything I've tried so far gives me this output:
{"success":"0","error":"Unable to Authorize Request - Check Your Post Data"}

I think my problem is in one or both parts.

Part 1:
cryptsy website says:
An additional security element must be passed into the post:
Their supplied PHP code has:
PHP:
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$post_data = "method=getinfo&nonce=1"

I think the B4A equivalent is:
B4X:
job_cryptsy_connect.PostString("https://api.cryptsy.com/api","method=getinfo&nonce=1")

Does part 1 look right?

Part 2:
cryptsy website says:
Authorization is performed by sending the following variables into the request header:
Key — Public API key. An example API key: 5a8808b25e3f59d8818d3fbc0ce993fbb82dcf90

Sign — ALL POST data (param=val&param1=val1) signed by a secret key according to HMAC-SHA512 method.
Their supplied PHP code has:
PHP:
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$headers = Array("Sign: 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "Key: 01234567890abcdef01234567890abcdef012345")

I haven't been able to find a way to Send these variables into the request header. It seems like it should be a subset of PostString but there doesn't seem to be anything there. I also looked into GetRequest.SetHeader but that's a different type of request and seems to just set the request format anyway. If someone could point me in the right direction of how to put variables into the header I'd really appreciate it!
 
Last edited:
Upvote 0

cyiwin

Active Member
Licensed User
Longtime User
I'm pretty sure I need to use:
B4X:
job.GetRequest.SetHeader
to send my "Sign" and "Key". but how is it done when you have two variables?
For example:
B4X:
job.GetRequest.SetHeader("Sign&Key", "0a1b2c3d4e5f&c3d2f8s3")
does not work, I've tried many ways but no success...
 
Upvote 0

cyiwin

Active Member
Licensed User
Longtime User
I have decided to use nonce=1 for testing purposes, it works fine with nonce=1 with the php program and keeps my "sign" the same each time.

From research it looks like these settings should work.
B4X:
job.PostString("https://api.cryptsy.com/api","method=getinfo&nonce=1")
job.GetRequest.SetHeader("sign","1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
job.GetRequest.SetHeader("key","1234567890abcdef1234567890abcdef12345678")
job.GetRequest.SetContentType("application/x-www-form-urlencoded")

But sadly they do not, I hope someone might have an idea...
 
Upvote 0

cyiwin

Active Member
Licensed User
Longtime User
Whew! I finally found my post issue, and only took me four days! I now know more than I ever wanted to know about post requests. My problem turned out to be a head slapper, I was sending cryptsy capital Hex instead of lower case. It makes sense, a capital "A" uses a different byte than a lower case "a", still I wish the receiving end had programming to accept either. I also learned that it is hard to get your wife and children to share in the excitement of a website accepting your first post request.

Here is the code:

Libraries: ByteConverter, Encryption, HTTP, HttpUtils2, StringFunctions

B4X:
Sub Globals
  Dim sf As StringFunctions
  Dim job_GetInfo As HttpJob
  Dim API_Key, API_Secret, API_Signed As String
  Dim Post_URL, Post_Data As String
  Dim Byte_Conv As ByteConverter
End Sub

Sub Activity_Create(FirstTime As Boolean)
  If FirstTime Then
    sf.Initialize
  End If
    
  Post_URL = "https://api.cryptsy.com/api"
  API_Key = "0123456789abcdef0123456789abcdef01234567"   
  API_Secret = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
  Post_Data = "method=getinfo&nonce=1"
       
  Dim Sign() As Byte = HashHmac(Post_Data, API_Secret)
       
  API_Signed = Byte_Conv.HexFromBytes(Sign)             'convert to HEX
  API_Signed = sf.Lower(API_Signed)                     'convert to lower hex
           
  Get_Job
End Sub

Sub Get_Job
  Dim job_GetInfo As HttpJob

  job_GetInfo.Initialize("job_GetInfo", Me)
  job_GetInfo.PostString(Post_URL, Post_Data)
  job_GetInfo.GetRequest.SetHeader("Sign", API_Signed)
  job_GetInfo.GetRequest.SetHeader("Key", API_Key)

  'Stuff that appears unnecessary but since others use it.....
  job_GetInfo.GetRequest.SetHeader("User-Agent","Mozilla/4.0 (compatible; Cryptsy API B4A client)")
  job_GetInfo.GetRequest.SetContentType("application/x-www-form-urlencoded")

End Sub

Sub JobDone(job As HttpJob)
  Log("JobName = " & job.JobName & ", Success = " & job.Success)

  If job.Success = True Then
    Select job.JobName
      Case "job_GetInfo"
        'print the result to the logs
        Log(job.GetString)
    End Select   
  Else
    Log("Error: " & job.ErrorMessage)
    ToastMessageShow("Error: " & job.ErrorMessage, True)
  End If

  job.Release
End Sub

Sub HashHmac(data As String, secret As String) As Byte()
  Dim m As Mac                                                                                            'm As Message Authentication Code
  Dim kg As KeyGenerator                                                                        'kg As KeyGenerator
  kg.Initialize("HmacSHA512")                                                                'initialize kg using HmacSHA512 algorithm
  kg.KeyFromBytes(secret.GetBytes("UTF8"))                                    'encode string "secret" to an array of Bytes using UTF8
  m.Initialise("HmacSHA512", kg.Key)                                                'initialize m using HmacSHA512 algorithm and the secret key
  m.Update(data.GetBytes("UTF8"))                                                        'encodes post data to an array of Bytes and loads it to be signed
  Return m.Sign                                                                                            'sign the loaded data using the secret key, return the calc signature data
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

I'm currently always using nonce = 1 and it is working but I will use some sort of time stamp later. I think cryptsy wants it in the form of an integer.

Thanks to Erel and DonManfred for the help!
 
Upvote 0

carlos7000

Well-Known Member
Licensed User
Longtime User
Whew! I finally found my post issue, and only took me four days! I now know more than I ever wanted to know about post requests. My problem turned out to be a head slapper, I was sending cryptsy capital Hex instead of lower case. It makes sense, a capital "A" uses a different byte than a lower case "a", still I wish the receiving end had programming to accept either. I also learned that it is hard to get your wife and children to share in the excitement of a website accepting your first post request.

Here is the code:

Libraries: ByteConverter, Encryption, HTTP, HttpUtils2, StringFunctions

B4X:
Sub Globals
  Dim sf As StringFunctions
  Dim job_GetInfo As HttpJob
  Dim API_Key, API_Secret, API_Signed As String
  Dim Post_URL, Post_Data As String
  Dim Byte_Conv As ByteConverter
End Sub

Sub Activity_Create(FirstTime As Boolean)
  If FirstTime Then
    sf.Initialize
  End If
   
  Post_URL = "https://api.cryptsy.com/api"
  API_Key = "0123456789abcdef0123456789abcdef01234567"  
  API_Secret = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
  Post_Data = "method=getinfo&nonce=1"
      
  Dim Sign() As Byte = HashHmac(Post_Data, API_Secret)
      
  API_Signed = Byte_Conv.HexFromBytes(Sign)             'convert to HEX
  API_Signed = sf.Lower(API_Signed)                     'convert to lower hex
          
  Get_Job
End Sub

Sub Get_Job
  Dim job_GetInfo As HttpJob

  job_GetInfo.Initialize("job_GetInfo", Me)
  job_GetInfo.PostString(Post_URL, Post_Data)
  job_GetInfo.GetRequest.SetHeader("Sign", API_Signed)
  job_GetInfo.GetRequest.SetHeader("Key", API_Key)

  'Stuff that appears unnecessary but since others use it.....
  job_GetInfo.GetRequest.SetHeader("User-Agent","Mozilla/4.0 (compatible; Cryptsy API B4A client)")
  job_GetInfo.GetRequest.SetContentType("application/x-www-form-urlencoded")

End Sub

Sub JobDone(job As HttpJob)
  Log("JobName = " & job.JobName & ", Success = " & job.Success)

  If job.Success = True Then
    Select job.JobName
      Case "job_GetInfo"
        'print the result to the logs
        Log(job.GetString)
    End Select  
  Else
    Log("Error: " & job.ErrorMessage)
    ToastMessageShow("Error: " & job.ErrorMessage, True)
  End If

  job.Release
End Sub

Sub HashHmac(data As String, secret As String) As Byte()
  Dim m As Mac                                                                                            'm As Message Authentication Code
  Dim kg As KeyGenerator                                                                        'kg As KeyGenerator
  kg.Initialize("HmacSHA512")                                                                'initialize kg using HmacSHA512 algorithm
  kg.KeyFromBytes(secret.GetBytes("UTF8"))                                    'encode string "secret" to an array of Bytes using UTF8
  m.Initialise("HmacSHA512", kg.Key)                                                'initialize m using HmacSHA512 algorithm and the secret key
  m.Update(data.GetBytes("UTF8"))                                                        'encodes post data to an array of Bytes and loads it to be signed
  Return m.Sign                                                                                            'sign the loaded data using the secret key, return the calc signature data
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

I'm currently always using nonce = 1 and it is working but I will use some sort of time stamp later. I think cryptsy wants it in the form of an integer.

Thanks to Erel and DonManfred for the help!

Hi. I'm trying to log in to bittrex. The bittrex example code is for php. This is the example code en php:

B4X:
$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);

Try to use the code of this post but I can not find the encrypt and StringFunctions library.

¿Could you help me?
 
Upvote 0
Top