fix message encryption/decryption

This commit is contained in:
Ivan Socolsky 2015-02-18 18:14:24 -03:00
parent 9b6c5716b4
commit 33800aff7e
5 changed files with 32 additions and 25 deletions

View File

@ -15,7 +15,7 @@ var ServerCompromisedError = require('./servercompromisederror')
var BASE_URL = 'http://localhost:3001/copay/api'; 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) { function _encryptProposalMessage(message, encryptingKey) {
if (!message) return null; if (!message) return null;
@ -24,7 +24,11 @@ function _encryptProposalMessage(message, encryptingKey) {
function _decryptProposalMessage(message, encryptingKey) { function _decryptProposalMessage(message, encryptingKey) {
if (!message) return ''; if (!message) return '';
return WalletUtils.decryptMessage(message, encryptingKey); try {
return WalletUtils.decryptMessage(message, encryptingKey);
} catch (ex) {
return '<ECANNOTDECRYPT>';
}
}; };
function _parseError(body) { function _parseError(body) {
@ -150,8 +154,9 @@ API.prototype._doGetRequest = function(url, data, cb) {
API.prototype._initData = function(network, walletPrivKey, m, n) { API.prototype._initData = function(network, walletPrivKey, m, n) {
var xPrivKey = new Bitcore.HDPrivateKey(network); 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 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 copayerId = WalletUtils.xPubToCopayerId(xPubKey);
var data = { var data = {
@ -161,8 +166,9 @@ API.prototype._initData = function(network, walletPrivKey, m, n) {
network: network, network: network,
m: m, m: m,
n: n, n: n,
signingPrivKey: signingPrivKey, signingPrivKey: signingPrivKey.toWIF(),
walletPrivKey: walletPrivKey.toWIF(), walletPrivKey: walletPrivKey.toWIF(),
sharedEncryptingKey: sharedEncryptingKey,
}; };
return data; return data;
}; };
@ -280,8 +286,8 @@ API.prototype.getStatus = function(cb) {
var url = '/v1/wallets/'; var url = '/v1/wallets/';
self._doGetRequest(url, data, function(err, body) { self._doGetRequest(url, data, function(err, body) {
_.each(body.pendingTxps, function(txp) { _.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); return cb(err, body, data.copayerId);
}); });
@ -312,7 +318,7 @@ API.prototype.sendTxProposal = function(opts, cb) {
var args = { var args = {
toAddress: opts.toAddress, toAddress: opts.toAddress,
amount: amount, amount: amount,
message: _encryptProposalMessage(opts.message, data.signingPrivKey), message: _encryptProposalMessage(opts.message, data.sharedEncryptingKey),
}; };
var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message); var hash = WalletUtils.getProposalHash(args.toAddress, args.amount, args.message);
args.proposalSignature = WalletUtils.signMessage(hash, data.signingPrivKey); args.proposalSignature = WalletUtils.signMessage(hash, data.signingPrivKey);
@ -417,7 +423,7 @@ API.prototype.getTxProposals = function(opts, cb) {
if (err) return cb(err); if (err) return cb(err);
_.each(txps, function(txp) { _.each(txps, function(txp) {
txp.message = _decryptProposalMessage(txp.message, data.signingPrivKey); txp.message = _decryptProposalMessage(txp.message, data.sharedEncryptingKey);
}); });
return cb(null, txps); return cb(null, txps);
}); });

View File

@ -83,20 +83,18 @@ WalletUtils.fromSecret = function(secret) {
}; };
WalletUtils.encryptMessage = function(message, privKey) { WalletUtils.encryptMessage = function(message, encryptingKey) {
var hash = sjcl.hash.sha256.hash(privKey); var key = sjcl.codec.base64.toBits(encryptingKey);
var key = sjcl.codec.utf8String.toBits(hash); //key = sjcl.bitArray.clamp(key, 128);
key = sjcl.bitArray.clamp(key, 128);
return sjcl.encrypt(key, message, { return sjcl.encrypt(key, message, {
ks: 128, ks: 128,
iter: 1 iter: 1
}); });
}; };
WalletUtils.decryptMessage = function(cyphertextJson, privKey) { WalletUtils.decryptMessage = function(cyphertextJson, encryptingKey) {
var hash = sjcl.hash.sha256.hash(privKey); var key = sjcl.codec.base64.toBits(encryptingKey);
var key = sjcl.codec.utf8String.toBits(hash); //key = sjcl.bitArray.clamp(key, 128);
key = sjcl.bitArray.clamp(key, 128);
return sjcl.decrypt(key, cyphertextJson); return sjcl.decrypt(key, cyphertextJson);
}; };

View File

@ -177,7 +177,7 @@ describe('client API ', function() {
statusCode: 200 statusCode: 200
}, TestData.serverResponse.pendingTxs); }, TestData.serverResponse.pendingTxs);
client.request = request; client.request = request;
client.getTxProposals({}, function(err, x) { client.getTxProposals({}, function(err, x) {
should.not.exist(err); should.not.exist(err);
x.length.should.equal(1); x.length.should.equal(1);
@ -194,6 +194,7 @@ describe('client API ', function() {
describe('#sendTxProposal ', function() { describe('#sendTxProposal ', function() {
it('should send tx proposal with encrypted message', function(done) { 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 response = {};
var request = sinon.mock().yields(null, { var request = sinon.mock().yields(null, {
statusCode: 200 statusCode: 200
@ -210,7 +211,7 @@ describe('client API ', function() {
callArgs.toAddress.should.equal(args.toAddress); callArgs.toAddress.should.equal(args.toAddress);
callArgs.amount.should.equal(20000); callArgs.amount.should.equal(20000);
callArgs.message.should.not.equal(args.message); 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); decryptedMsg.should.equal(args.message);
done(); done();
}); });

View File

@ -28,17 +28,19 @@ var storage = {
"publicKeyRing": ["xpub661MyMwAqRbcGzNFbVQLh6CV6ukHuhBn4Bf4CGrQ6pFfNNdJ3pxrEVDtFHGsTzyz6Py23FhP8GWAqew3PsvnstEs2iayH1PK5Mx1bSVSEAG", "xpub661MyMwAqRbcGH2FXudWPDdrRobZ9XWTGaz18AnN1gkG8QW9ZUcn63RcK5qJJ5DXYXeAWBNqprdvvg8VHA5twmBHCUc6gWygXkwmU1Dohwh"], "publicKeyRing": ["xpub661MyMwAqRbcGzNFbVQLh6CV6ukHuhBn4Bf4CGrQ6pFfNNdJ3pxrEVDtFHGsTzyz6Py23FhP8GWAqew3PsvnstEs2iayH1PK5Mx1bSVSEAG", "xpub661MyMwAqRbcGH2FXudWPDdrRobZ9XWTGaz18AnN1gkG8QW9ZUcn63RcK5qJJ5DXYXeAWBNqprdvvg8VHA5twmBHCUc6gWygXkwmU1Dohwh"],
"copayerId": "020b41cfea5fae42050580474a195a8385b093f291af4079759851d8819383a680", "copayerId": "020b41cfea5fae42050580474a195a8385b093f291af4079759851d8819383a680",
"signingPrivKey": "KyhU3befBaePqHuPQNNyY1XFUgnArR3GUKZpZwV5vS7u1pcR3uzB", "signingPrivKey": "KyhU3befBaePqHuPQNNyY1XFUgnArR3GUKZpZwV5vS7u1pcR3uzB",
"sharedEncryptingKey": "ezDRS2NRchMJLf1IWtjL5A==",
"network": "livenet" "network": "livenet"
}, },
complete11: { complete11: {
"copayerId": "02da4d1bd797b41a5565fe54f22583051bd3c29dbbc86eedadb6af6e9200af1048", "copayerId": "036ed70f51adf14e3e55aba727d28adec1851aff6865552aa9ec9b9dbafecd4a87",
"xPrivKey": "tprv8ZgxMBicQKsPeCyWCzmvnAkJUBEKpqggFmEmaR6CeyHeJj8oB8uFRWZonK7qLD1ih35tiRr1xnXg9a2rGLiYGQWVgvjhubzuUvVyanPXNuU", "xPrivKey": "tprv8ZgxMBicQKsPdjYWSKKh8SuMZAQ6K3J6v5H3A8ZVyyvXk4h1xft3qeRTmCZbxQB77n3ndfF6G4AevqgpiAVuCmZqYURH3wzSQviTvP1nkYN",
"publicKeyRing": ["tpubD6NzVbkrYhZ4Xg1J6eSXBaQR3CkFzAsaq4qYrw8W5F639DPZoXiqc1BfxSR2J1muzEE2qq7rZEDUgwyuwv1nYQgA9uorLghrT76FE5CjAuz"], "publicKeyRing": ["tpubD6NzVbkrYhZ4XCaJKxzHXrZU8Bv2UNV1VNspSeboQFivaYwnb4he293KwLPxnNNSBEj3RAE5EEaHqPWatzexGd613hGMLLQz5BEgjtpgWnZ"],
"network": "testnet", "network": "testnet",
"m": 1, "m": 1,
"n": 1, "n": 1,
"signingPrivKey": "Kzs8tquNTCsxwbEB9RiSNmcti4QXaW1i9UyLBV329VM5zU7o5nGB", "signingPrivKey": "KxyNf4A1Td61GMrnC6LNQYsfE9zKvgsFmmgkPYrPoJHva4j9YSL1",
"walletPrivKey": "L259i9W123MrrEjBUTzPVvo3ZMoJV26WB7Abr9LcVsiuWpj6sEL1" "walletPrivKey": "L4JHs2ZggZkEuRLffH2WVe337nwZWMxytxViLLGyAfGREk6bUCXo",
"sharedEncryptingKey": "ezDRS2NRchMJLf1IWtjL5A=="
}, },
}; };
@ -141,7 +143,7 @@ var serverResponse = {
creatorId: '02da4d1bd797b41a5565fe54f22583051bd3c29dbbc86eedadb6af6e9200af1048', creatorId: '02da4d1bd797b41a5565fe54f22583051bd3c29dbbc86eedadb6af6e9200af1048',
toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5', toAddress: 'n2TBMPzPECGUfcT2EByiTJ12TPZkhN2mN5',
amount: 10000, 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', changeAddress: '2Mu4nmHhBWFk766M4yXJi2oyi59HZLKHWqn',
inputs: [{ inputs: [{
address: '2MvBhgsQX6EusXvNGdcjM5dschDkaos1uuk', address: '2MvBhgsQX6EusXvNGdcjM5dschDkaos1uuk',

View File

@ -68,7 +68,7 @@ describe('WalletUtils', function() {
describe('#encryptMessage #decryptMessage round trip', function() { describe('#encryptMessage #decryptMessage round trip', function() {
it('should encrypt and decrypt', function() { it('should encrypt and decrypt', function() {
var pwd = '0dea92f1df6675085b5cdd965487bb862f84f2755bcb56fa45dbf5b387a6c4a0'; var pwd = "ezDRS2NRchMJLf1IWtjL5A==";
var ct = WalletUtils.encryptMessage('hello world', pwd); var ct = WalletUtils.encryptMessage('hello world', pwd);
var msg = WalletUtils.decryptMessage(ct, pwd); var msg = WalletUtils.decryptMessage(ct, pwd);
msg.should.equal('hello world'); msg.should.equal('hello world');