Merge pull request #768 from ryanxcharles/feature/authentication
Authentication
This commit is contained in:
commit
c16531dfb7
9 changed files with 330 additions and 32 deletions
82
js/models/core/Message.js
Normal file
82
js/models/core/Message.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
'use strict';
|
||||
|
||||
var imports = require('soop').imports();
|
||||
var bitcore = require('bitcore');
|
||||
|
||||
/* Encrypted, authenticated messages to be shared between copayers */
|
||||
var Message = function() {
|
||||
};
|
||||
|
||||
Message.encode = function(topubkey, fromkey, payload) {
|
||||
var version = new Buffer([0]);
|
||||
var toencrypt = Buffer.concat([version, payload]);
|
||||
var encrypted = Message._encrypt(topubkey, toencrypt);
|
||||
var sig = Message._sign(fromkey, encrypted);
|
||||
var encoded = {
|
||||
pubkey: fromkey.public.toString('hex'),
|
||||
sig: sig.toString('hex'),
|
||||
encrypted: encrypted.toString('hex')
|
||||
};
|
||||
return encoded;
|
||||
};
|
||||
|
||||
Message.decode = function(key, encoded) {
|
||||
try {
|
||||
var frompubkey = new Buffer(encoded.pubkey, 'hex');
|
||||
} catch (e) {
|
||||
throw new Error('Error decoding public key: ' + e);
|
||||
}
|
||||
|
||||
try {
|
||||
var sig = new Buffer(encoded.sig, 'hex');
|
||||
var encrypted = new Buffer(encoded.encrypted, 'hex');
|
||||
} catch (e) {
|
||||
throw new Error('Error decoding data: ' + e);
|
||||
}
|
||||
|
||||
try {
|
||||
var v = Message._verify(frompubkey, sig, encrypted);
|
||||
} catch (e) {
|
||||
throw new Error('Error verifying signature: ' + e);
|
||||
}
|
||||
|
||||
if (!v)
|
||||
throw new Error('Invalid signature');
|
||||
|
||||
try {
|
||||
var decrypted = Message._decrypt(key.private, encrypted);
|
||||
} catch (e) {
|
||||
throw new Error('Cannot decrypt data: ' + e);
|
||||
}
|
||||
|
||||
if (decrypted[0] !== 0)
|
||||
throw new Error('Invalid version number');
|
||||
|
||||
if (decrypted.length === 0)
|
||||
throw new Error('No data present');
|
||||
|
||||
var payload = decrypted.slice(1);
|
||||
return payload;
|
||||
};
|
||||
|
||||
Message._encrypt = function(topubkey, payload, r, iv) {
|
||||
var encrypted = bitcore.ECIES.encrypt(topubkey, payload, r, iv);
|
||||
return encrypted;
|
||||
};
|
||||
|
||||
Message._decrypt = function(privkey, encrypted) {
|
||||
var decrypted = bitcore.ECIES.decrypt(privkey, encrypted);
|
||||
return decrypted;
|
||||
};
|
||||
|
||||
Message._sign = function(key, payload) {
|
||||
var sig = bitcore.Message.sign(payload, key);
|
||||
return sig;
|
||||
};
|
||||
|
||||
Message._verify = function(pubkey, signature, payload) {
|
||||
var v = bitcore.Message.verifyWithPubKey(pubkey, payload, signature);
|
||||
return v;
|
||||
};
|
||||
|
||||
module.exports = require('soop')(Message);
|
||||
|
|
@ -32,9 +32,17 @@ PrivateKey.prototype.getIdPriv = function() {
|
|||
return this.idpriv;
|
||||
};
|
||||
|
||||
PrivateKey.prototype.getIdKey = function() {
|
||||
if (!this.idkey) {
|
||||
this.cacheId();
|
||||
}
|
||||
return this.idkey;
|
||||
};
|
||||
|
||||
PrivateKey.prototype.cacheId = function() {
|
||||
var path = Structure.IdFullBranch;
|
||||
var idhk = this.bip.derive(path);
|
||||
this.idkey = idhk.eckey;
|
||||
this.id = idhk.eckey.public.toString('hex');
|
||||
this.idpriv = idhk.eckey.private.toString('hex');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ Wallet.prototype.netStart = function(callback) {
|
|||
|
||||
var myId = self.getMyCopayerId();
|
||||
var myIdPriv = self.getMyCopayerIdPriv();
|
||||
|
||||
var startOpts = {
|
||||
copayerId: myId,
|
||||
privkey: myIdPriv,
|
||||
|
|
|
|||
|
|
@ -224,7 +224,8 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras
|
|||
this.log('\t### PrivateKey Initialized');
|
||||
var opts = {
|
||||
copayerId: privateKey.getId(),
|
||||
privkey: privateKey.getIdPriv()
|
||||
privkey: privateKey.getIdPriv(),
|
||||
key: privateKey.getIdKey()
|
||||
};
|
||||
self.network.cleanUp();
|
||||
self.network.start(opts, function() {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ var EventEmitter = imports.EventEmitter || require('events').EventEmitter;
|
|||
var bitcore = require('bitcore');
|
||||
var util = bitcore.util;
|
||||
var extend = require('util')._extend;
|
||||
var Message = require('../core/Message');
|
||||
/*
|
||||
* Emits
|
||||
* 'connect'
|
||||
|
|
@ -45,6 +46,7 @@ Network.prototype.cleanUp = function() {
|
|||
this.connectedPeers = [];
|
||||
this.peerId = null;
|
||||
this.privkey = null; //TODO: hide privkey in a closure
|
||||
this.key = null;
|
||||
this.copayerId = null;
|
||||
this.signingKey = null;
|
||||
this.allowedCopayerIds = null;
|
||||
|
|
@ -151,16 +153,29 @@ Network.prototype._addConnectedCopayer = function(copayerId, isInbound) {
|
|||
this.emit('connect', copayerId);
|
||||
};
|
||||
|
||||
Network.prototype._onData = function(enchex, isInbound, peerId) {
|
||||
var sig, payload;
|
||||
var encUint8Array = new Uint8Array(enchex);
|
||||
Network.prototype.getKey = function() {
|
||||
if (!this.key) {
|
||||
var key = new bitcore.Key();
|
||||
key.private = new Buffer(this.privkey, 'hex');
|
||||
key.regenerateSync();
|
||||
this.key = key;
|
||||
}
|
||||
return this.key;
|
||||
};
|
||||
|
||||
Network.prototype._onData = function(enc, isInbound, peerId) {
|
||||
var encUint8Array = new Uint8Array(enc);
|
||||
var encbuf = new Buffer(encUint8Array);
|
||||
var encstr = encbuf.toString();
|
||||
|
||||
var privkey = this.privkey;
|
||||
var key = this.getKey();
|
||||
|
||||
try {
|
||||
var data = this._decrypt(privkey, encbuf);
|
||||
payload = JSON.parse(data);
|
||||
var encoded = JSON.parse(encstr);
|
||||
var databuf = this._decode(key, encoded);
|
||||
var datastr = databuf.toString();
|
||||
var payload = JSON.parse(datastr);
|
||||
} catch (e) {
|
||||
this._deletePeer(peerId);
|
||||
return;
|
||||
|
|
@ -169,6 +184,13 @@ Network.prototype._onData = function(enchex, isInbound, peerId) {
|
|||
if (isInbound && payload.type === 'hello') {
|
||||
var payloadStr = JSON.stringify(payload);
|
||||
|
||||
//ensure claimed public key is actually the public key of the peer
|
||||
//e.g., their public key should hash to be their peerId
|
||||
if (peerId.toString() !== this.peerFromCopayer(payload.copayerId) || peerId.toString() !== this.peerFromCopayer(encoded.pubkey)) {
|
||||
this._deletePeer(peerId, 'incorrect pubkey for peerId');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.allowedCopayerIds && !this.allowedCopayerIds[payload.copayerId]) {
|
||||
this._deletePeer(peerId);
|
||||
return;
|
||||
|
|
@ -349,18 +371,20 @@ Network.prototype.getPeer = function() {
|
|||
return this.peer;
|
||||
};
|
||||
|
||||
Network.prototype._encrypt = function(pubkey, payload) {
|
||||
var encrypted = bitcore.ECIES.encrypt(pubkey, payload);
|
||||
return encrypted;
|
||||
Network.prototype._encode = function(topubkey, fromkey, payload) {
|
||||
var encoded = Message.encode(topubkey, fromkey, payload);
|
||||
return encoded;
|
||||
};
|
||||
|
||||
|
||||
Network.prototype._decrypt = function(privkey, encrypted) {
|
||||
var decrypted = bitcore.ECIES.decrypt(privkey, encrypted);
|
||||
return decrypted;
|
||||
Network.prototype._decode = function(key, encoded) {
|
||||
var payload = Message.decode(key, encoded);
|
||||
return payload;
|
||||
};
|
||||
|
||||
Network.prototype._sendToOne = function(copayerId, payload, sig, cb) {
|
||||
Network.prototype._sendToOne = function(copayerId, payload, cb) {
|
||||
if (!Buffer.isBuffer(payload))
|
||||
throw new Error('payload must be a buffer');
|
||||
var peerId = this.peerFromCopayer(copayerId);
|
||||
if (peerId !== this.peerId) {
|
||||
var dataConn = this.connections[peerId];
|
||||
|
|
@ -383,7 +407,6 @@ Network.prototype.send = function(copayerIds, payload, cb) {
|
|||
if (typeof copayerIds === 'string')
|
||||
copayerIds = [copayerIds];
|
||||
|
||||
var sig;
|
||||
var payloadStr = JSON.stringify(payload);
|
||||
var payloadBuf = new Buffer(payloadStr);
|
||||
|
||||
|
|
@ -391,8 +414,9 @@ Network.prototype.send = function(copayerIds, payload, cb) {
|
|||
var i = 0;
|
||||
copayerIds.forEach(function(copayerId) {
|
||||
var copayerIdBuf = new Buffer(copayerId, 'hex');
|
||||
var encPayload = self._encrypt(copayerIdBuf, payloadBuf);
|
||||
self._sendToOne(copayerId, encPayload, sig, function() {
|
||||
var encPayload = self._encode(copayerIdBuf, self.getKey(), payloadBuf);
|
||||
var enc = new Buffer(JSON.stringify(encPayload));
|
||||
self._sendToOne(copayerId, enc, function() {
|
||||
if (++i === l && typeof cb === 'function') cb();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue