I have two problem with hmac
First:
$klucz = "";
$url = "";
$nazwaUsera = "";
$nazwaKlucza = "faktura";
$curlHandle = curl_init($url);
$hashWiadomosci = hmac($klucz, $url .$nazwaUsera.$nazwaKlucza);
$headers = array(
'Accept: application/pdf',
'Content-type: application/pdf; charset = UTF-8',
'Authentication: IAPIS user='.$nazwaUsera.', hmac-
sha1='.$hashWiadomosci
);
if is hmac problem is: Fatal error: Uncaught Error: Call to undefined function hmac()
Bat if is
$klucz = "";
$url = "";
$nazwaUsera = "";
$nazwaKlucza = "faktura";
$curlHandle = curl_init($url);
$hashWiadomosci = hash_hmac($klucz, $url, $nazwaUsera.$nazwaKlucza);
$headers = array(
'Accept: application/pdf',
'Content-type: application/pdf; charset = UTF-8',
'Authentication: IAPIS user='.$nazwaUsera.', hmac-
sha1='.$hashWiadomosci
);
problem is: Warning: hash_hmac(): Unknown hashing algorithm: EC8A18CEC9D1F1B2
how solved this?
Try this:
hashWiadomosci = hash_hmac('sha256', $klucz . $url, $nazwaUsera.$nazwaKlucza);
First parameter must be the hash algorithm you need to be used (you can call hash_algos to inspect supported algorithms in your platform. I.E. md5", "sha256", "haval160,4".
Related
I converted the following Python code from the official docs(https://docs.sandbox.gemini.com/rest-api/#private-api-invocation) to PHP but I always get InvalidSignature error:
url = "https://api.gemini.com/v1/mytrades"
gemini_api_key = "mykey"
gemini_api_secret = "1234abcd".encode()
t = datetime.datetime.now()
payload_nonce = time.time()
payload = {"request": "/v1/mytrades", "nonce": payload_nonce}
encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
signature = hmac.new(gemini_api_secret, b64, hashlib.sha384).hexdigest()
request_headers = {
'Content-Type': "text/plain",
'Content-Length': "0",
'X-GEMINI-APIKEY': gemini_api_key,
'X-GEMINI-PAYLOAD': b64,
'X-GEMINI-SIGNATURE': signature,
'Cache-Control': "no-cache"
}
response = requests.post(url, headers=request_headers)
My PHP code is this and everything looks correct:
$b64 = base64_encode(utf8_encode(json_encode([ "request" => "/v1/balances", "nonce" => time() ])));
$header = [
'Content-Type: text/plain',
'Content-Length: 0',
'X-GEMINI-APIKEY: master-XXXXXXX',
'X-GEMINI-PAYLOAD: ' . $b64,
'X-GEMINI-SIGNATURE: ' . md5(hash_hmac('sha384', utf8_encode('XXXXXXXXXX'), $b64)),
'Cache-Control: no-cache'
];
$ch = curl_init('https://api.sandbox.gemini.com/v1/balances');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
echo curl_exec($ch);
Error:
{"result":"error","reason":"InvalidSignature","message":"InvalidSignature"}
I don't have any access to the API, but could you please try the following chagnes:
Remove the MD5 function from the signature calculation. The hash_hmac function in PHP already does this by default.
'X-GEMINI-SIGNATURE: ' . hash_hmac('sha384', utf8_encode('XXXXXXXXXX'), $b64),
Switch around the payload and the key in the same line:
'X-GEMINI-SIGNATURE: ' . hash_hmac('sha384', $b64, utf8_encode('XXXXXXXXXX')),
I found a sample github that is able to properly generate a signature for the API in question, their code is as follows:
so i found their github which has a sample in object oriented like this:
if ($api === 'private') {
$this->check_required_credentials();
$timestamp = $this->seconds();
$xPhemexRequestExpiry = $this->safe_integer($this->options, 'x-phemex-request-expiry', 60);
$expiry = $this->sum($timestamp, $xPhemexRequestExpiry);
$expiryString = (string) $expiry;
$headers = array(
'x-phemex-access-token' => $this->apiKey,
'x-phemex-request-expiry' => $expiryString,
);
$payload = '';
if ($method === 'POST') {
$payload = $this->json($params);
$body = $payload;
$headers['Content-Type'] = 'application/json';
}
$auth = $requestPath . $queryString . $expiryString . $payload;
$headers['x-phemex-request-signature'] = $this->hmac($this->encode($auth), $this->encode($this->secret));
}
$url = $this->urls['api'][$api] . $url;
return array( 'url' => $url, 'method' => $method, 'body' => $body, 'headers' => $headers );
}
my code is core and looks like this, and I can not seem to get the proper result of a valid signature, any guidance possible?
$epoch=strtotime(date('r', time()).'+2 days');
$data = '{"clOrdId":"123456","ordType":"LIMIT","symbol":"BTC-USD","side":"BUY","orderQty":"0.1","price":"100"}';
$content=("/orders".$epoch.$data);
//SECRET KEY
$str = 'cn87t3Z8wLw-OR626cuAZFIUhHT2z3XSfEt6X8OBSyFjU3Ny05ZWYyLTQ3ZjItODkwNy1mODlhNWMxM2UzMWY';
$decode= base64_decode($str);
$signature = hash_hmac('SHA256',$content,'$decode');
In short I need to send the signature inside the headers like so:
"x-phemex-request-signature: $signature)",
UPDATED CODE:
$epoch=strtotime(date('r', time()).'+5 minutes');
$data = '{"clOrdId":"123456","ordType":"LIMIT","symbol":"BTC-USD","side":"BUY","orderQty":"0.1","price":"100"}';
$content="/orders".$epoch.$data;
//SECRET KEY
$str = 'cn87t3Z8wLw-OR626cuAZFIUhHT2z3XSfEt6X8OBSyFkMjE0NjU3Ny05ZWYyLTQ3ZjItODkwNy1mODlhNWMxM2UzMWY';
$signature = hash_hmac('SHA256',$auth,'cn87t3Z8wLw-OR626cuAZFIUhHT2z3XSfEt6X8OBSy***5ZWYyLTQ3ZjItODkwNy1mODlhNWMxM2UzMWY');
$headers = array(
"accept: application/json",
//API KEY
"x-phemex-access-token:e92028ca-4704-4317-8149-c1c7a7f85226",
"Content-Type: application/json",
"x-phemex-request-expiry: $epoch",
//this right here is what we need to have working proper
"x-phemex-request-signature: $signature)",
);
The format of a proper signature looks like:
API REST Request URL: https://api.phemex.com/orders
Request Path: /orders
Request Query:
Request Body: {"symbol":"BTCUSD","clOrdID":"uuid-1573058952273","side":"Sell","priceEp":93185000,"orderQty":7,"ordType":"Limit","reduceOnly":false,"timeInForce":"GoodTillCancel","takeProfitEp":0,"stopLossEp":0}
Request Expiry: 1575735514
Signature: HMacSha256( /orders + 1575735514 + {"symbol":"BTCUSD","clOrdID":"uuid-1573058952273","side":"Sell","priceEp":93185000,"orderQty":7,"ordType":"Limit","reduceOnly":false,"timeInForce":"GoodTillCancel","takeProfitEp":0,"stopLossEp":0})
signed string is /orders1575735514{"symbol":"BTCUSD","clOrdID":"uuid-1573058952273","side":"Sell","priceEp":93185000,"orderQty":7,"ordType":"Limit","reduceOnly":false,"timeInForce":"GoodTillCancel","takeProfitEp":0,"stopLossEp":0}
I have the API request as outlined below which works fine (given the correct replacement of "xxxyyy"!) however I want to perform this call simultaneously with up to 5-10 different remote URLs. In the example below I've shown just 1 remote URL however I have an array of 10,000 urls which I would like to query as quickly as possible, all of which return the same structure in JSON.
After researching the topic I believe this can be done in PHP using Curl Multi, does anyone know if this is true, if so how would I go about this so i can call say 10 at once rather than each one individually?
<?php
$username = "xxxyyyxxxyyyxxxyyyxxxyyy";
$password = "xxxyyyxxxyyyxxxyyyxxxyyyxxxyyyxxxyyyxxxyyyxxxyyy";
$remote_url_1 = 'https://xxxyyyxxxyyyxxxyyyxxxyyy_1.json';
{
$headers = array();
$headers[] = "Authorization: Basic " . base64_encode("$username:$password");
$headers[] = "X-Page:" . $pages;
$opts = array(
'http'=>array(
'method'=>"GET",
'header' => $headers
)
);
$context = stream_context_create($opts);
$file1 = file_get_contents($remote_url, false, $context);
$data = json_decode($file1, true);
$data2 = (array_values($data));
$orderline_id = $data2[0];
$orderline_sale_number = $data2[1];
$orderline_status = $data2[2];
$orderline_notes = $data2[3];
}
}
?>
I have been trying to follow the steps laid out in the docs for twitter sign in here: https://dev.twitter.com/docs/auth/implementing-sign-twitter
My Code:
$oauth_consumer_secret = '***';
$access_token_secret = '***';
$oauth_consumer_key = '***';
$oauth_nonce = createNonce();
$oauth_signature_method = 'HMAC-SHA1';
$oauth_time = time();
$oauth_token = '***';
$oauth_version = '1.0';
$oauth = array(
'oauth_callback' => '***',
'oauth_consumer_key'=>$oauth_consumer_key,
'oauth_nonce'=>$oauth_nonce,
'oauth_signature_method'=>$oauth_signature_method,
'oauth_timestamp'=>$oauth_time,
'oauth_token'=>$oauth_token,
'oauth_version'=>$oauth_version
);
$baseURI = 'https://api.twitter.com/1.1/oauth/request_token';
$baseString = buildBaseString($baseURI,$oauth);
$compositeKey = getCompositeKey($oauth_consumer_secret,null);
$oauth_signature = base64_encode(hash_hmac('sha1', $baseString, $compositeKey, true));
$oauth['oauth_signature'] = $oauth_signature; //add the signature to our oauth array
$header = array(buildAuthorizationHeader($oauth));
$login = loginUser($baseURI,$header);
echo $login;
function loginUser($baseURI,$header){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $baseURI);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
$output = curl_exec($ch);
curl_close($ch);
if ($output!=''){
return $output;
} else {
return 'fail';
};
};
function buildBaseString($baseURI,$params){
$r = array(); // temp array
ksort($params); // sorts params alphabetically by key
foreach($params as $key=>$value){
$r[] = '$key='.rawurlencode($value);
};
return 'POST&'.rawurlencode($baseURI).'&'.rawurlencode(implode('&', $r)); // returns complete base string
};
// Create composite key
function getCompositeKey($consumerSecret,$requestToken){
return rawurlencode($consumerSecret) . '&' . rawurlencode($requestToken);
};
function createNonce(){
$characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
$string = '';
for ($i=0; $i<32; $i++) {
$string .= $characters[rand(0, strlen($characters) - 1)];
};
return $string;
};
function buildAuthorizationHeader($oauth){
$r = 'Authorization: OAuth '; //header prefix
$values = array(); //temporary key=value array
foreach($oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\""; //encode key=value string
$r .= implode(', ', $values); //reassemble
return $r; //return full authorization header
};
The Problem I am having is that I am getting no response what so ever! So the login function just keeps returning 'fail'.
When I change curlopt_ssl_verifypeer to false I get a HTTP/1.1 401 Unauthorized error.
Any help or clues would be appreciated.
The SSL and OAuth issues are most likely separate.
As for SSL, your certificate authoririty (CA) bundle is most likely out of date. You can either tell curl to not verify the peer CURLOPT_SSL_VERIFYPEER = 0 or update the CA bundle. You can download a current CA bundle here. Most people (myself included) just turn off VERIFYPEER. Although this practice should be discouraged, it's a common solution.
When generating the request token, you do not need oauth_token in your oauth parameters. You are asking for a request token, you don't have one yet. Not sure if this matters, but only use ',' as the delimiter, not ', ' as in $r .= implode(', ', $values); //reassemble
I looked through the rest of your implementation and it looks right. Having written my own, I can appreciate the difficulty here.
I have spent the past couple of hours trying all types of variations but according to the Twitter API this should have worked from step 1!
1 addition I have made to the script below is that I have added in:
$header = array("Expect:");
This I found helped in another question on stackoverflow from getting a denied issue / 100-continue.
Issue:
Failed to validate oauth signature and token is the response EVERY time!!!
Example of my post data:
Array ( [oauth_callback] => http://www.mysite.com//index.php [oauth_consumer_key] => hidden [oauth_nonce] => hidden [oauth_signature_method] => HMAC-SHA1 [oauth_timestamp] => 1301270847 [oauth_version] => 1.0 )
And my header data:
Array ( [0] => Expect: )
Script:
$consumer_key = "hidden";
$consumer_secret = "hidden";
function Post_Data($url,$data,$header){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
$data['oauth_callback'] = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$data['oauth_consumer_key'] = $consumer_key;
$data['oauth_nonce'] = md5(time());
$data['oauth_signature_method'] = "HMAC-SHA1";
$data['oauth_timestamp'] = time();
$data['oauth_version'] = "1.0";
$header = array("Expect:");
$content = Post_Data("http://api.twitter.com/oauth/request_token",$data,$header);
print_r($content);
Can anybody see an obvious mistake that I may be making here? Preferably I would not like to go with somebody elses code as most examples have full classes & massive functions, I am looking for the most simple approach!
Your problem is that you did not include the OAuth signature in your request.
You can read about the concept on this page.
A working implementation can be found here.
I faced same issue, what I was missing is passing header in to the curl request.
As shown in this question, I was also sending the $header = array('Expect:'), which was the problem in my case. I started sending signature in header with other data as below and it solved the case for me.
$header = calculateHeader($parameters, 'https://api.twitter.com/oauth/request_token');
function calculateHeader(array $parameters, $url)
{
// redefine
$url = (string) $url;
// divide into parts
$parts = parse_url($url);
// init var
$chunks = array();
// process queries
foreach($parameters as $key => $value) $chunks[] = str_replace('%25', '%', urlencode_rfc3986($key) . '="' . urlencode_rfc3986($value) . '"');
// build return
$return = 'Authorization: OAuth realm="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '", ';
$return .= implode(',', $chunks);
// prepend name and OAuth part
return $return;
}
function urlencode_rfc3986($value)
{
if(is_array($value)) return array_map('urlencode_rfc3986', $value);
else
{
$search = array('+', ' ', '%7E', '%');
$replace = array('%20', '%20', '~', '%25');
return str_replace($search, $replace, urlencode($value));
}
}