bitcore-wallet-service icon indicating copy to clipboard operation
bitcore-wallet-service copied to clipboard

How/where to get value of x-identity and x-signature using bitcore?

Open Lalitpatadiya12 opened this issue 7 years ago • 17 comments

I can not find the value of Authentication header from the docs

x-identity : Identity is the Peer-ID x-signature : Signature is the current request signature

can any one have idea please let me know

Lalitpatadiya12 avatar Oct 05 '17 04:10 Lalitpatadiya12

From bitcore-wallet-client:

/**
 * Sign an HTTP request
 * @private
 * @static
 * @memberof Client.API
 * @param {String} method - The HTTP method
 * @param {String} url - The URL for the request
 * @param {Object} args - The arguments in case this is a POST/PUT request
 * @param {String} privKey - Private key to sign the request
 */
API._signRequest = function(method, url, args, privKey) {
  var message = [method.toLowerCase(), url, JSON.stringify(args)].join('|');
  return Utils.signMessage(message, privKey);
};

Utils.signMessage

Utils.signMessage = function(text, privKey) {
  $.checkArgument(text);
  var priv = new PrivateKey(privKey);
  var hash = Utils.hashMessage(text);
  return crypto.ECDSA.sign(hash, priv, 'little').toString();
};
Utils.hashMessage = function(text) {
  $.checkArgument(text);
  var buf = new Buffer(text);
  var ret = crypto.Hash.sha256sha256(buf);
  ret = new Bitcore.encoding.BufferReader(ret).readReverse();
  return ret;
};

So basically, x-signature should be:

  1. method (get or post) | url | JSON.stringify(args) is the message, if GET request, JSON is just "{}"
    • example: get|https://bws.bitpay.com/bws/v1/getfee?someArg=23&r=2763|{} or post|https://bws.bitpay.com/bws/v1/postsomething|{"someArg":23,"r":2763}
  2. double sha256 hash the message. (Note: the library reverses the bytes, and then passes 'little' to the ECDSA library from bitcore-lib which reverses the bytes again... kinda weird.)
  3. sign the message using ECDSA. Getting the r and s values (using low S)
  4. the x-signature is a stringify of sig

Edit: ECDSA was using the .sig attribute for sign.

dabura667 avatar Oct 05 '17 07:10 dabura667

@dabura667 Thank for immediate reply, I am beginner so i need some more clear detail, if you have please give me step by step process what should i do, and more thing what about peer- ID..?

Lalitpatadiya12 avatar Oct 05 '17 07:10 Lalitpatadiya12

If you are a beginner, just use bitcore-wallet to interact with BWS.

dabura667 avatar Oct 05 '17 08:10 dabura667

@dabura667 does bitcore-wallet give all feature of bitcore wallet service ..?

Lalitpatadiya12 avatar Oct 05 '17 12:10 Lalitpatadiya12

yes. bitcore-wallet-service is server-side, bitcore-wallet is the client software that talks to the BWS server.

dabura667 avatar Oct 05 '17 12:10 dabura667

@dabura667 means using bitcore-wallet-service i can not generate multiple address right..?

Lalitpatadiya12 avatar Oct 05 '17 12:10 Lalitpatadiya12

Hi @dabura667 I'm trying to create the signature for the message from a PHP based system, and I don't seem to be able to recreate the signature correctly The error I am getting:

info Client Err: 401 /v1/addresses/ {"code":"NOT_AUTHORIZED","message":"Invalid signature"} 
<> ::ffff:127.0.0.1 2018-03-16T00:51:50.913Z "GET /bws/api/v1/addresses/" 401 55 2.451 "GuzzleHttp/6.2.1 curl/7.47.0 PHP/7.1.15-1+ubuntu16.04.1+deb.sury.org+2

I am using this PHP library https://github.com/simplito/elliptic-php

My code:

$message = implode('|',[strtolower($method), $url, json_encode($args)]);
$ec = new EC('secp256k1');
$key = KeyPair::fromPrivate($ec, $this->requestSigningKey, 'hex');
$signature = $key->sign($message);
$derSign = $signature->toDER('hex');

Any help much appreciated.

robertclarkson avatar Mar 16 '18 01:03 robertclarkson

Two things:

  1. Is json_encode the exact same as JS JSON.stringify?
  2. What hash algorithm does sign() use? It must be sha256(sha256(message))

dabura667 avatar Mar 16 '18 13:03 dabura667

Also the signature must be low-S.

I suck at reading PHP, sorry.

dabura667 avatar Mar 16 '18 13:03 dabura667

@dabura667 Thanks for the help so far. No worries at all, don't expect you to be fluent in all languages.

  1. json_encode appears to be the same, in any case there are no args with the get request.
  2. sign doesnt use sha256(sha256()) so I have modified the code to do this, unfortunately with no further change
$ec = new EC('secp256k1');
$key = KeyPair::fromPrivate($ec, $this->requestSigningKey, 'hex');
$data = hash('sha256', hash('sha256', $message));
$signature = $key->sign($data);
$derSign = $signature->toDER('hex');

as far as Low-s goes, $signature holds a Signature object that has an $r and a $s and a $recovery param

the toDer('hex') function seems to combine the $r and $s with padding in some way and return the result encoded in hex

I've tried using the string value of $s from the signature, this was encoded in base10 and didnt work either.

robertclarkson avatar Mar 19 '18 20:03 robertclarkson

@dabura667 I should add I'm dumping the message in the bitcore backend and I can see it's formulated correctly / the same as the requests from the copay client. I'm sure the issue is with the signature somehow. I'm not reversing the message or setting 'little' for the endian anywhere, so maybe this could be the issue?

robertclarkson avatar Mar 19 '18 20:03 robertclarkson

If you are unsure about little endian, flip the byte order before passing to sign.

Also, just to clarify, sign doesn’t do any hashing at all? Most libraries default to SHA1, so you could be SHA1-ing the double SHA256.

Also, to calculate low-s, check if s > n/2 (where n is the order of the secp256k1 curve) and if it is, you should replace s with n - s

Let me know if that helps.

dabura667 avatar Mar 19 '18 23:03 dabura667

Also, remember to use the right private key for signing key.

dabura667 avatar Mar 19 '18 23:03 dabura667

Thanks @dabura667 I'm signing with the key in the .wallet.dat referenced as "requestPrivKey"

I've looked in the sign function and I can't see any hashing, although I have to say its getting a bit over my head, I'm not an encryption guru unfortunately.

It seems to be getting truncated, then something next, but no idea, almost unreadable. :)

$msg = $this->_truncateToN(new BN($msg, 16));

...

$s = $k->invm($this->n)->mul($r->mul($key->getPrivate())->iadd($msg));
            

https://github.com/simplito/elliptic-php/blob/f18586ff8c26830a9f5476e7dc8d2ab5623f80f9/lib/EC.php#L91

Is low-s the result i need to send? or am i supposed to calculate the signature with a parameter low-s set? (sorry im totally lacking knowledge in this area)

robertclarkson avatar Mar 20 '18 01:03 robertclarkson

Holy shit i just tried another library and got it working. So for anyone else trying to do this, try this other library "BitcoinECDSA" :

$message = implode('|',[strtolower($method), $url, json_encode($args,JSON_FORCE_OBJECT)]);
$data = hash('sha256', hex2bin(hash('sha256', $message)));
$bitcoinECDSA = new BitcoinECDSA();
$bitcoinECDSA->setPrivateKey($this->requestSigningKey);
$signedMessage = $bitcoinECDSA->signHash($data);

Thank you @dabura667 for all your help!

robertclarkson avatar Mar 20 '18 01:03 robertclarkson

There seems to be a problem with this library in that when it signs it can produce R values that are negative which goes against BIP-0066. https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki

robertclarkson avatar Mar 20 '18 01:03 robertclarkson

Hey @dabura667 One more thing, how is the proposalsSignature generated for a transaction proposal? Thanks!

robertclarkson avatar Mar 20 '18 04:03 robertclarkson