From 78033f7c979acacc37c140fdcbd21967cc08105e Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Tue, 17 Feb 2015 22:50:12 -0300 Subject: [PATCH 1/3] add encrypt/decrypt methods --- lib/walletutils.js | 19 +++++++++++++++++-- package.json | 3 ++- test/walletutils.js | 9 +++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/walletutils.js b/lib/walletutils.js index bfecf60..823f25e 100644 --- a/lib/walletutils.js +++ b/lib/walletutils.js @@ -5,6 +5,7 @@ var PrivateKey = Bitcore.PrivateKey; var PublicKey = Bitcore.PublicKey; var crypto = Bitcore.crypto; var HDPath = require('./hdpath'); +var sjcl = require('sjcl'); function WalletUtils() {}; @@ -61,8 +62,9 @@ WalletUtils.xPubToCopayerId = function(xpub) { return (new Bitcore.HDPublicKey(xpub)).derive(HDPath.IdBranch).publicKey.toString(); }; +<< << << < HEAD WalletUtils.toSecret = function(walletId, walletPrivKey, network) { - return walletId + ':' + walletPrivKey.toWIF() + ':' + (network == 'testnet' ? 'T' : 'L'); + return walletId + ':' + walletPrivKey.toWIF() + ':' + (network == 'testnet' ? 'T' : 'L'); }; WalletUtils.fromSecret = function(secret) { @@ -72,7 +74,7 @@ WalletUtils.fromSecret = function(secret) { var networkChar = secretSplit[2]; - return { + return { walletId: walletId, walletPrivKey: walletPrivKey, network: networkChar == 'T' ? 'testnet' : 'livenet', @@ -80,6 +82,19 @@ WalletUtils.fromSecret = function(secret) { }; +WalletUtils.encryptMessage = function(message, password) { + var key = sjcl.codec.utf8String.toBits(password); + key = sjcl.bitArray.clamp(key, 256); + return sjcl.encrypt(key, message, { + ks: 256, + iter: 1 + }); +}; +WalletUtils.decryptMessage = function(cyphertextJson, password) { + var key = sjcl.codec.utf8String.toBits(password); + key = sjcl.bitArray.clamp(key, 256); + return sjcl.decrypt(key, cyphertextJson); +}; module.exports = WalletUtils; diff --git a/package.json b/package.json index 4298698..bcca48e 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,9 @@ "morgan": "*", "npmlog": "^0.1.1", "preconditions": "^1.0.7", - "request": "^2.53.0", "qr-image": "*", + "request": "^2.53.0", + "sjcl": "^1.0.2", "uuid": "*" }, "devDependencies": { diff --git a/test/walletutils.js b/test/walletutils.js index 0addd17..1383885 100644 --- a/test/walletutils.js +++ b/test/walletutils.js @@ -65,4 +65,13 @@ describe('WalletUtils', function() { WalletUtils.verifyMessage(aLongerText, sig, aPubKey).should.equal(true); }); }); + + describe('#encryptMessage #decryptMessage round trip', function() { + it('should encrypt and decrypt', function() { + var pwd = '0dea92f1df6675085b5cdd965487bb862f84f2755bcb56fa45dbf5b387a6c4a0'; + var ct = WalletUtils.encryptMessage('hello world', pwd); + var msg = WalletUtils.decryptMessage(ct, pwd); + msg.should.equal('hello world'); + }); + }); }); From 58d46c0ad5f310500e7125544fa99384e2a97a8f Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Wed, 18 Feb 2015 10:49:18 -0300 Subject: [PATCH 2/3] encrypt/decrypt proposal message in client api --- lib/client/api.js | 30 ++++++++++++++++++++++++++---- lib/walletutils.js | 11 ++++++----- test/integration/clientApi.js | 32 +++++++++++++++++++++++++++++--- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/lib/client/api.js b/lib/client/api.js index 167df6e..63a5a88 100644 --- a/lib/client/api.js +++ b/lib/client/api.js @@ -18,9 +18,24 @@ var BASE_URL = 'http://localhost:3001/copay/api'; var WALLET_CRITICAL_DATA = ['xPrivKey', 'm', 'publicKeyRing']; function _createProposalOpts(opts, signingKey) { - var hash = WalletUtils.getProposalHash(opts.toAddress, opts.amount, opts.message); - opts.proposalSignature = WalletUtils.signMessage(hash, signingKey); - return opts; + var args = { + toAddress: opts.toAddress, + amount: opts.amount, + message: _encryptProposalMessage(opts.message, signingKey), + }; + var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message); + args.proposalSignature = WalletUtils.signMessage(hash, signingKey); + return args; +}; + +function _encryptProposalMessage(message, encryptingKey) { + if (!message) return null; + return WalletUtils.encryptMessage(message, encryptingKey); +}; + +function _decryptProposalMessage(message, encryptingKey) { + if (!message) return ''; + return WalletUtils.decryptMessage(message, encryptingKey); }; function _parseError(body) { @@ -392,7 +407,14 @@ API.prototype.getTxProposals = function(opts, cb) { this._loadAndCheck(function(err, data) { if (err) return cb(err); var url = '/v1/txproposals/'; - self._doGetRequest(url, data, cb); + self._doGetRequest(url, data, function(err, txps) { + if (err) return cb(err); + + _.each(txps, function(txp) { + txp.message = self._decryptProposalMessage(txp.message, data.signingPrivKey); + }); + return cb(null, txps); + }); }); }; diff --git a/lib/walletutils.js b/lib/walletutils.js index 823f25e..fbce875 100644 --- a/lib/walletutils.js +++ b/lib/walletutils.js @@ -62,7 +62,6 @@ WalletUtils.xPubToCopayerId = function(xpub) { return (new Bitcore.HDPublicKey(xpub)).derive(HDPath.IdBranch).publicKey.toString(); }; -<< << << < HEAD WalletUtils.toSecret = function(walletId, walletPrivKey, network) { return walletId + ':' + walletPrivKey.toWIF() + ':' + (network == 'testnet' ? 'T' : 'L'); }; @@ -82,8 +81,9 @@ WalletUtils.fromSecret = function(secret) { }; -WalletUtils.encryptMessage = function(message, password) { - var key = sjcl.codec.utf8String.toBits(password); +WalletUtils.encryptMessage = function(message, privKey) { + var hash = sjcl.hash.sha256.hash(privKey); + var key = sjcl.codec.utf8String.toBits(hash); key = sjcl.bitArray.clamp(key, 256); return sjcl.encrypt(key, message, { ks: 256, @@ -91,8 +91,9 @@ WalletUtils.encryptMessage = function(message, password) { }); }; -WalletUtils.decryptMessage = function(cyphertextJson, password) { - var key = sjcl.codec.utf8String.toBits(password); +WalletUtils.decryptMessage = function(cyphertextJson, privKey) { + var hash = sjcl.hash.sha256.hash(privKey); + var key = sjcl.codec.utf8String.toBits(hash); key = sjcl.bitArray.clamp(key, 256); return sjcl.decrypt(key, cyphertextJson); }; diff --git a/test/integration/clientApi.js b/test/integration/clientApi.js index d1e1891..947c9ea 100644 --- a/test/integration/clientApi.js +++ b/test/integration/clientApi.js @@ -8,6 +8,7 @@ var Client = require('../../lib/client'); var API = Client.API; var Bitcore = require('bitcore'); var TestData = require('./clienttestdata'); +var WalletUtils = require('../../lib/walletutils'); describe('client API ', function() { var client; @@ -156,14 +157,14 @@ describe('client API ', function() { client.export(function(err, str) { should.not.exist(err); - client.storage.fs.readFile = sinon.stub().yields(null); - client.import(str, function(err,wallet) { + client.storage.fs.readFile = sinon.stub().yields(null); + client.import(str, function(err, wallet) { should.not.exist(err); var wallet = JSON.parse(client.storage.fs.writeFile.getCall(0).args[1]); TestData.storage.complete22.should.deep.equal(wallet); done(); - }); + }); }); }); }); @@ -172,6 +173,31 @@ describe('client API ', function() { it.skip('Should recreate a wallet acording stored data', function(done) {}); }); + describe('#sendTxProposal ', function() { + it('should send tx proposal with encrypted message', function(done) { + var response = {}; + var request = sinon.mock().yields(null, { + statusCode: 200 + }, response); + client.request = request; + + var args = { + toAddress: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq', + amount: 100000, + message: 'some message', + }; + client.sendTxProposal(args, function(err) { + var callArgs = request.getCall(0).args[0].body; + callArgs.toAddress.should.equal(args.toAddress); + callArgs.amount.should.equal(args.amount); + callArgs.message.should.not.equal(args.message); + var decryptedMsg = WalletUtils.decryptMessage(callArgs.message, '42798f82c4ed9ace4d66335165071edf180e70bc0fc08dacb3e35185a2141d5b'); + decryptedMsg.should.equal(args.message); + done(); + }); + }); + }); + describe('#signTxProposal ', function() { it.skip('should sign tx proposal', function(done) {}); From 90bb3e8b18c0d9c583b4512a6833d314a533b95a Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Wed, 18 Feb 2015 10:51:45 -0300 Subject: [PATCH 3/3] change key_size to 128bits on message encryption --- lib/walletutils.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/walletutils.js b/lib/walletutils.js index fbce875..184cb5b 100644 --- a/lib/walletutils.js +++ b/lib/walletutils.js @@ -84,9 +84,9 @@ WalletUtils.fromSecret = function(secret) { WalletUtils.encryptMessage = function(message, privKey) { var hash = sjcl.hash.sha256.hash(privKey); var key = sjcl.codec.utf8String.toBits(hash); - key = sjcl.bitArray.clamp(key, 256); + key = sjcl.bitArray.clamp(key, 128); return sjcl.encrypt(key, message, { - ks: 256, + ks: 128, iter: 1 }); }; @@ -94,7 +94,7 @@ WalletUtils.encryptMessage = function(message, privKey) { WalletUtils.decryptMessage = function(cyphertextJson, privKey) { var hash = sjcl.hash.sha256.hash(privKey); var key = sjcl.codec.utf8String.toBits(hash); - key = sjcl.bitArray.clamp(key, 256); + key = sjcl.bitArray.clamp(key, 128); return sjcl.decrypt(key, cyphertextJson); };