fix message encryption/decryption
This commit is contained in:
parent
9b6c5716b4
commit
33800aff7e
|
@ -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 '';
|
||||||
|
try {
|
||||||
return WalletUtils.decryptMessage(message, encryptingKey);
|
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,7 +286,7 @@ 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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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');
|
||||||
|
|
Loading…
Reference in New Issue