From 33800aff7ecaa5c5cb37e20dd348303c454ac927 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Wed, 18 Feb 2015 18:14:24 -0300 Subject: [PATCH] fix message encryption/decryption --- lib/client/api.js | 22 ++++++++++++++-------- lib/walletutils.js | 14 ++++++-------- test/integration/clientApi.js | 5 +++-- test/integration/clienttestdata.js | 14 ++++++++------ test/walletutils.js | 2 +- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/lib/client/api.js b/lib/client/api.js index 2783609..7f97a92 100644 --- a/lib/client/api.js +++ b/lib/client/api.js @@ -15,7 +15,7 @@ var ServerCompromisedError = require('./servercompromisederror') var BASE_URL = 'http://localhost:3001/copay/api'; -var WALLET_CRITICAL_DATA = ['xPrivKey', 'm', 'publicKeyRing']; +var WALLET_CRITICAL_DATA = ['xPrivKey', 'm', 'publicKeyRing', 'sharedEncryptingKey']; function _encryptProposalMessage(message, encryptingKey) { if (!message) return null; @@ -24,7 +24,11 @@ function _encryptProposalMessage(message, encryptingKey) { function _decryptProposalMessage(message, encryptingKey) { if (!message) return ''; - return WalletUtils.decryptMessage(message, encryptingKey); + try { + return WalletUtils.decryptMessage(message, encryptingKey); + } catch (ex) { + return ''; + } }; function _parseError(body) { @@ -150,8 +154,9 @@ API.prototype._doGetRequest = function(url, data, cb) { API.prototype._initData = function(network, walletPrivKey, m, n) { var xPrivKey = new Bitcore.HDPrivateKey(network); - var signingPrivKey = (new Bitcore.HDPrivateKey(xPrivKey)).derive('m/1/0').privateKey.toWIF(); var xPubKey = (new Bitcore.HDPublicKey(xPrivKey)).toString(); + var signingPrivKey = (new Bitcore.HDPrivateKey(xPrivKey)).derive('m/1/0').privateKey; + var sharedEncryptingKey = Bitcore.crypto.Hash.sha256(signingPrivKey.toBuffer()).slice(0, 16).toString('base64'); var copayerId = WalletUtils.xPubToCopayerId(xPubKey); var data = { @@ -161,8 +166,9 @@ API.prototype._initData = function(network, walletPrivKey, m, n) { network: network, m: m, n: n, - signingPrivKey: signingPrivKey, + signingPrivKey: signingPrivKey.toWIF(), walletPrivKey: walletPrivKey.toWIF(), + sharedEncryptingKey: sharedEncryptingKey, }; return data; }; @@ -280,8 +286,8 @@ API.prototype.getStatus = function(cb) { var url = '/v1/wallets/'; self._doGetRequest(url, data, function(err, body) { _.each(body.pendingTxps, function(txp) { - txp.message = _decryptProposalMessage(txp.message, data.signingPrivKey); - }); + txp.message = _decryptProposalMessage(txp.message, data.sharedEncryptingKey); + }); return cb(err, body, data.copayerId); }); @@ -312,7 +318,7 @@ API.prototype.sendTxProposal = function(opts, cb) { var args = { toAddress: opts.toAddress, amount: amount, - message: _encryptProposalMessage(opts.message, data.signingPrivKey), + message: _encryptProposalMessage(opts.message, data.sharedEncryptingKey), }; var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message); args.proposalSignature = WalletUtils.signMessage(hash, data.signingPrivKey); @@ -417,7 +423,7 @@ API.prototype.getTxProposals = function(opts, cb) { if (err) return cb(err); _.each(txps, function(txp) { - txp.message = _decryptProposalMessage(txp.message, data.signingPrivKey); + txp.message = _decryptProposalMessage(txp.message, data.sharedEncryptingKey); }); return cb(null, txps); }); diff --git a/lib/walletutils.js b/lib/walletutils.js index dabd89c..f342054 100644 --- a/lib/walletutils.js +++ b/lib/walletutils.js @@ -83,20 +83,18 @@ 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, 128); +WalletUtils.encryptMessage = function(message, encryptingKey) { + var key = sjcl.codec.base64.toBits(encryptingKey); + //key = sjcl.bitArray.clamp(key, 128); return sjcl.encrypt(key, message, { ks: 128, iter: 1 }); }; -WalletUtils.decryptMessage = function(cyphertextJson, privKey) { - var hash = sjcl.hash.sha256.hash(privKey); - var key = sjcl.codec.utf8String.toBits(hash); - key = sjcl.bitArray.clamp(key, 128); +WalletUtils.decryptMessage = function(cyphertextJson, encryptingKey) { + var key = sjcl.codec.base64.toBits(encryptingKey); + //key = sjcl.bitArray.clamp(key, 128); return sjcl.decrypt(key, cyphertextJson); }; diff --git a/test/integration/clientApi.js b/test/integration/clientApi.js index d820989..864069d 100644 --- a/test/integration/clientApi.js +++ b/test/integration/clientApi.js @@ -177,7 +177,7 @@ describe('client API ', function() { statusCode: 200 }, TestData.serverResponse.pendingTxs); client.request = request; - + client.getTxProposals({}, function(err, x) { should.not.exist(err); x.length.should.equal(1); @@ -194,6 +194,7 @@ describe('client API ', function() { describe('#sendTxProposal ', function() { it('should send tx proposal with encrypted message', function(done) { + client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.complete11)); var response = {}; var request = sinon.mock().yields(null, { statusCode: 200 @@ -210,7 +211,7 @@ describe('client API ', function() { callArgs.toAddress.should.equal(args.toAddress); callArgs.amount.should.equal(20000); callArgs.message.should.not.equal(args.message); - var decryptedMsg = WalletUtils.decryptMessage(callArgs.message, '42798f82c4ed9ace4d66335165071edf180e70bc0fc08dacb3e35185a2141d5b'); + var decryptedMsg = WalletUtils.decryptMessage(callArgs.message, TestData.storage.complete11.sharedEncryptingKey); decryptedMsg.should.equal(args.message); done(); }); diff --git a/test/integration/clienttestdata.js b/test/integration/clienttestdata.js index c390ae0..6a1da29 100644 --- a/test/integration/clienttestdata.js +++ b/test/integration/clienttestdata.js @@ -28,17 +28,19 @@ var storage = { "publicKeyRing": ["xpub661MyMwAqRbcGzNFbVQLh6CV6ukHuhBn4Bf4CGrQ6pFfNNdJ3pxrEVDtFHGsTzyz6Py23FhP8GWAqew3PsvnstEs2iayH1PK5Mx1bSVSEAG", "xpub661MyMwAqRbcGH2FXudWPDdrRobZ9XWTGaz18AnN1gkG8QW9ZUcn63RcK5qJJ5DXYXeAWBNqprdvvg8VHA5twmBHCUc6gWygXkwmU1Dohwh"], "copayerId": "020b41cfea5fae42050580474a195a8385b093f291af4079759851d8819383a680", "signingPrivKey": "KyhU3befBaePqHuPQNNyY1XFUgnArR3GUKZpZwV5vS7u1pcR3uzB", + "sharedEncryptingKey": "ezDRS2NRchMJLf1IWtjL5A==", "network": "livenet" }, complete11: { - "copayerId": "02da4d1bd797b41a5565fe54f22583051bd3c29dbbc86eedadb6af6e9200af1048", - "xPrivKey": "tprv8ZgxMBicQKsPeCyWCzmvnAkJUBEKpqggFmEmaR6CeyHeJj8oB8uFRWZonK7qLD1ih35tiRr1xnXg9a2rGLiYGQWVgvjhubzuUvVyanPXNuU", - "publicKeyRing": ["tpubD6NzVbkrYhZ4Xg1J6eSXBaQR3CkFzAsaq4qYrw8W5F639DPZoXiqc1BfxSR2J1muzEE2qq7rZEDUgwyuwv1nYQgA9uorLghrT76FE5CjAuz"], + "copayerId": "036ed70f51adf14e3e55aba727d28adec1851aff6865552aa9ec9b9dbafecd4a87", + "xPrivKey": "tprv8ZgxMBicQKsPdjYWSKKh8SuMZAQ6K3J6v5H3A8ZVyyvXk4h1xft3qeRTmCZbxQB77n3ndfF6G4AevqgpiAVuCmZqYURH3wzSQviTvP1nkYN", + "publicKeyRing": ["tpubD6NzVbkrYhZ4XCaJKxzHXrZU8Bv2UNV1VNspSeboQFivaYwnb4he293KwLPxnNNSBEj3RAE5EEaHqPWatzexGd613hGMLLQz5BEgjtpgWnZ"], "network": "testnet", "m": 1, "n": 1, - "signingPrivKey": "Kzs8tquNTCsxwbEB9RiSNmcti4QXaW1i9UyLBV329VM5zU7o5nGB", - "walletPrivKey": "L259i9W123MrrEjBUTzPVvo3ZMoJV26WB7Abr9LcVsiuWpj6sEL1" + "signingPrivKey": "KxyNf4A1Td61GMrnC6LNQYsfE9zKvgsFmmgkPYrPoJHva4j9YSL1", + "walletPrivKey": "L4JHs2ZggZkEuRLffH2WVe337nwZWMxytxViLLGyAfGREk6bUCXo", + "sharedEncryptingKey": "ezDRS2NRchMJLf1IWtjL5A==" }, }; @@ -141,7 +143,7 @@ var serverResponse = { creatorId: '02da4d1bd797b41a5565fe54f22583051bd3c29dbbc86eedadb6af6e9200af1048', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', amount: 10000, - message: '{"iv":"Ij6LjNp6Cjlrpx1MklQk9A==","v":1,"iter":1,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","ct":"uyxcL8bBgRS0W2KA"}', + message: '{"iv":"vDH4J15lBiokSP+iUS4ofA==","v":1,"iter":1,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","ct":"X/vPh+vh/Qv8IRSx"}', changeAddress: '2Mu4nmHhBWFk766M4yXJi2oyi59HZLKHWqn', inputs: [{ address: '2MvBhgsQX6EusXvNGdcjM5dschDkaos1uuk', diff --git a/test/walletutils.js b/test/walletutils.js index d8695eb..50e2082 100644 --- a/test/walletutils.js +++ b/test/walletutils.js @@ -68,7 +68,7 @@ describe('WalletUtils', function() { describe('#encryptMessage #decryptMessage round trip', function() { it('should encrypt and decrypt', function() { - var pwd = '0dea92f1df6675085b5cdd965487bb862f84f2755bcb56fa45dbf5b387a6c4a0'; + var pwd = "ezDRS2NRchMJLf1IWtjL5A=="; var ct = WalletUtils.encryptMessage('hello world', pwd); var msg = WalletUtils.decryptMessage(ct, pwd); msg.should.equal('hello world');