diff --git a/lib/client/Verifier.js b/lib/client/Verifier.js index dd01585..b671c39 100644 --- a/lib/client/Verifier.js +++ b/lib/client/Verifier.js @@ -4,7 +4,6 @@ var log = require('npmlog'); var Bitcore = require('bitcore'); var WalletUtils = require('../walletutils') -var SignUtils = require('../signutils'); /* * Checks data given by the server @@ -36,7 +35,7 @@ Verifier.checkCopayers = function(copayers, walletPrivKey, myXPrivKey, n) { } // Not signed pub keys - if (!SignUtils.verify(copayer.xPubKey, copayer.xPubKeySignature, walletPubKey)) { + if (!WalletUtils.verifyMessage(copayer.xPubKey, copayer.xPubKeySignature, walletPubKey)) { log.error('Invalid signatures in server response'); error = true; } @@ -56,7 +55,7 @@ Verifier.checkCopayers = function(copayers, walletPrivKey, myXPrivKey, n) { Verifier.checkTxProposal = function(data, txp) { var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.message); var signingPubKey = Bitcore.PrivateKey.fromString(data.signingPrivKey).toPublicKey().toString(); - if (!SignUtils.verify(hash, txp.proposalSignature, signingPubKey)) return false; + if (!WalletUtils.verifyMessage(hash, txp.proposalSignature, signingPubKey)) return false; return Verifier.checkAddress(data, txp.changeAddress); }; diff --git a/lib/client/api.js b/lib/client/api.js index 3f0cd56..c3e6428 100644 --- a/lib/client/api.js +++ b/lib/client/api.js @@ -9,7 +9,7 @@ var request = require('request') log.debug = log.verbose; var Bitcore = require('bitcore') -var SignUtils = require('../signutils'); +var WalletUtils = require('../walletutils'); var Verifier = require('./verifier'); var ServerCompromisedError = require('./servercompromisederror') @@ -17,7 +17,7 @@ var BASE_URL = 'http://localhost:3001/copay/api'; function _createProposalOpts(opts, signingKey) { var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message; - opts.proposalSignature = SignUtils.sign(msg, signingKey); + opts.proposalSignature = WalletUtils.signMessage(msg, signingKey); return opts; }; @@ -42,7 +42,7 @@ function _parseError(body) { function _signRequest(method, url, args, privKey) { var message = method.toLowerCase() + '|' + url + '|' + JSON.stringify(args); - return SignUtils.sign(message, privKey); + return WalletUtils.signMessage(message, privKey); }; function _createXPrivKey(network) { @@ -208,7 +208,7 @@ API.prototype._joinWallet = function(data, secret, copayerName, cb) { data.xPrivKey = _createXPrivKey(network); var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey); - var xPubKeySignature = SignUtils.sign(xPubKey.toString(), walletPrivKey); + var xPubKeySignature = WalletUtils.signMessage(xPubKey.toString(), walletPrivKey); var signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey; var args = { diff --git a/lib/server.js b/lib/server.js index 31b617a..ce3c3c6 100644 --- a/lib/server.js +++ b/lib/server.js @@ -18,7 +18,6 @@ var ClientError = require('./clienterror'); var Utils = require('./utils'); var Storage = require('./storage'); var WalletUtils = require('./walletutils'); -var SignUtils = require('./signutils'); var Wallet = require('./model/wallet'); var Copayer = require('./model/copayer'); @@ -152,7 +151,7 @@ CopayServer.prototype.getWallet = function(opts, cb) { * @param pubKey */ CopayServer.prototype._verifySignature = function(text, signature, pubKey) { - return SignUtils.verify(text, signature, pubKey); + return WalletUtils.verifyMessage(text, signature, pubKey); }; diff --git a/lib/signutils.js b/lib/signutils.js deleted file mode 100644 index c8913c1..0000000 --- a/lib/signutils.js +++ /dev/null @@ -1,43 +0,0 @@ -var _ = require('lodash'); -var Bitcore = require('bitcore'); -var PrivateKey = Bitcore.PrivateKey; -var PublicKey = Bitcore.PublicKey; -var Signature = Bitcore.crypto.Signature; -var ECDSA = Bitcore.crypto.ECDSA; -var Hash = Bitcore.crypto.Hash; -var BufferReader = Bitcore.encoding.BufferReader; - - - -var SignUtils = function() {}; - -/* TODO: It would be nice to be compatible with bitcoind signmessage. How - * the hash is calculated there? */ -SignUtils.hash = function(text) { - var buf = new Buffer(text); - var ret = Hash.sha256sha256(buf); - ret = new BufferReader(ret).readReverse(); - return ret; -}; - - -SignUtils.sign = function(text, privKey) { - var priv = new PrivateKey(privKey); - var hash = SignUtils.hash(text); - return ECDSA.sign(hash, priv, 'little').toString(); -}; - - -SignUtils.verify = function(text, signature, pubKey) { - var pub = new PublicKey(pubKey); - var hash = SignUtils.hash(text); - - try { - var sig = new Signature.fromString(signature); - return ECDSA.verify(hash, sig, pub, 'little'); - } catch (e) { - return false; - } -}; - -module.exports = SignUtils; diff --git a/lib/walletutils.js b/lib/walletutils.js index 57ecf48..68de114 100644 --- a/lib/walletutils.js +++ b/lib/walletutils.js @@ -1,10 +1,41 @@ var _ = require('lodash'); - var Bitcore = require('bitcore'); -var BitcoreAddress = Bitcore.Address; +var Address = Bitcore.Address; +var PrivateKey = Bitcore.PrivateKey; +var PublicKey = Bitcore.PublicKey; +var crypto = Bitcore.crypto; function WalletUtils() {}; +/* TODO: It would be nice to be compatible with bitcoind signmessage. How + * the hash is calculated there? */ +WalletUtils.hashMessage = function(text) { + var buf = new Buffer(text); + var ret = crypto.Hash.sha256sha256(buf); + ret = new Bitcore.encoding.BufferReader(ret).readReverse(); + return ret; +}; + + +WalletUtils.signMessage = function(text, privKey) { + var priv = new PrivateKey(privKey); + var hash = WalletUtils.hashMessage(text); + return crypto.ECDSA.sign(hash, priv, 'little').toString(); +}; + + +WalletUtils.verifyMessage = function(text, signature, pubKey) { + var pub = new PublicKey(pubKey); + var hash = WalletUtils.hashMessage(text); + + try { + var sig = new crypto.Signature.fromString(signature); + return crypto.ECDSA.verify(hash, sig, pub, 'little'); + } catch (e) { + return false; + } +}; + WalletUtils.deriveAddress = function(publicKeyRing, path, m, network) { var publicKeys = _.map(publicKeyRing, function(xPubKey) { @@ -12,7 +43,7 @@ WalletUtils.deriveAddress = function(publicKeyRing, path, m, network) { return xpub.derive(path).publicKey; }); - var bitcoreAddress = BitcoreAddress.createMultisig(publicKeys, m, network); + var bitcoreAddress = Address.createMultisig(publicKeys, m, network); return { address: bitcoreAddress.toString(), diff --git a/test/integration/server.js b/test/integration/server.js index fa9d7b2..51c0a53 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -12,7 +12,6 @@ var Bitcore = require('bitcore'); var Utils = require('../../lib/utils'); var WalletUtils = require('../../lib/walletutils'); -var SignUtils = require('../../lib/signutils'); var Storage = require('../../lib/storage'); var Wallet = require('../../lib/model/wallet'); @@ -179,7 +178,7 @@ helpers.createProposalOpts = function(toAddress, amount, message, signingKey) { }; var hash = WalletUtils.getProposalHash(opts.toAddress, opts.amount, opts.message); try { - opts.proposalSignature = SignUtils.sign(hash, signingKey); + opts.proposalSignature = WalletUtils.signMessage(hash, signingKey); } catch (ex) {} return opts; @@ -214,7 +213,7 @@ describe('Copay server', function() { .toString(); var message = 'hola'; - var sig = SignUtils.sign(message, priv); + var sig = WalletUtils.signMessage(message, priv); CopayServer.getInstanceWithAuth({ copayerId: wallet.copayers[0].id, diff --git a/test/signutils.js b/test/walletutils.js similarity index 68% rename from test/signutils.js rename to test/walletutils.js index 4acaddd..0addd17 100644 --- a/test/signutils.js +++ b/test/walletutils.js @@ -4,7 +4,7 @@ var _ = require('lodash'); var chai = require('chai'); var sinon = require('sinon'); var should = chai.should(); -var SignUtils = require('../lib/signutils'); +var WalletUtils = require('../lib/walletutils'); var aText = 'hola'; @@ -14,56 +14,55 @@ var aSignature = '3045022100d6186930e4cd9984e3168e15535e2297988555838ad10126d6c2 var otherPubKey = '02555a2d45e309c00cc8c5090b6ec533c6880ab2d3bc970b3943def989b3373f16'; -describe('SignUtils', function() { +describe('WalletUtils', function() { - describe('#hash', function() { + describe('#hashMessage', function() { it('Should create a hash', function() { - var res = SignUtils.hash(aText); + var res = WalletUtils.hashMessage(aText); res.toString('hex').should.equal('4102b8a140ec642feaa1c645345f714bc7132d4fd2f7f6202db8db305a96172f'); }); }); - describe('#sign', function() { - it('Should sign', function() { - var sig = SignUtils.sign(aText, aPrivKey); + describe('#signMessage', function() { + it('Should sign a message', function() { + var sig = WalletUtils.signMessage(aText, aPrivKey); should.exist(sig); sig.should.equal(aSignature); }); it('Should fail to sign with wrong args', function() { (function() { - SignUtils.sign(aText, aPubKey); + WalletUtils.signMessage(aText, aPubKey); }).should.throw('Number'); }); }); - describe('#verify', function() { + describe('#verifyMessage', function() { it('Should fail to verify a malformed signature', function() { - var res = SignUtils.verify(aText, 'badsignature', otherPubKey); + var res = WalletUtils.verifyMessage(aText, 'badsignature', otherPubKey); should.exist(res); res.should.equal(false); }); it('Should fail to verify a null signature', function() { - var res = SignUtils.verify(aText, null, otherPubKey); + var res = WalletUtils.verifyMessage(aText, null, otherPubKey); should.exist(res); res.should.equal(false); }); it('Should fail to verify with wrong pubkey', function() { - var res = SignUtils.verify(aText, aSignature, otherPubKey); + var res = WalletUtils.verifyMessage(aText, aSignature, otherPubKey); should.exist(res); res.should.equal(false); }); it('Should verify', function() { - var res = SignUtils.verify(aText, aSignature, aPubKey); + var res = WalletUtils.verifyMessage(aText, aSignature, aPubKey); should.exist(res); res.should.equal(true); }); }); - describe('#sign #verify round trip', function() { + describe('#signMessage #verifyMessage round trip', function() { it('Should sign and verify', function() { var aLongerText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; - var sig = SignUtils.sign(aLongerText, aPrivKey); - SignUtils.verify(aLongerText, sig, aPubKey).should.equal(true); + var sig = WalletUtils.signMessage(aLongerText, aPrivKey); + WalletUtils.verifyMessage(aLongerText, sig, aPubKey).should.equal(true); }); }); - });