Browse Source

Merge pull request #90 from matiu/bug/airgapped

Bug/airgapped
activeAddress
Ivan Socolsky 10 years ago
parent
commit
2ae7033866
  1. 11
      README.md
  2. 1
      bit-wallet/bit-import
  3. 21
      bit-wallet/bit-sign
  4. 11
      bit-wallet/cli-utils.js
  5. 5
      lib/client/api.js
  6. 2
      lib/client/verifier.js
  7. 4
      lib/walletutils.js

11
README.md

@ -124,7 +124,10 @@ bit import output.dat
``` ```
# Airgapped Operation # Airgapped Operation
## WARNING: THIS IS STILL WIP ##
Air gapped (non connected) devices are supported. This setup can be useful is maximun security is needed, to prevent private keys to get compromissed. In this setup a device is installed without network access, and transactions are signed off-line. Transactions can be pulled from the server using a `proxy` device, then downloaded to a pendrive to be moved to the air-gapped device, signed there and then moved back the `proxy` device to be send back to the server. Note that Private keys are generated off-line in the airgapped device. Air gapped (non connected) devices are supported. This setup can be useful is maximun security is needed, to prevent private keys to get compromissed. In this setup a device is installed without network access, and transactions are signed off-line. Transactions can be pulled from the server using a `proxy` device, then downloaded to a pendrive to be moved to the air-gapped device, signed there and then moved back the `proxy` device to be send back to the server. Note that Private keys are generated off-line in the airgapped device.
@ -133,10 +136,12 @@ Air gapped (non connected) devices are supported. This setup can be useful is ma
# On the Air-gapped device # On the Air-gapped device
airgapped$ bit genkey airgapped$ bit genkey
airgapped$ bit export -o wallet.dat --readonly #(or --readwrite if you need the proxy to be able to propose transactions) airgapped$ bit export -o toProxy --access readwrite #(or --readonly if proxy wont be allowed to propose transactions)
# On the proxy machine # On the proxy machine
proxy$ bit join secret -i wallet.dat proxy$ bit import toProxy
proxy$ bit join secret # Or bit create
proxy$ bit address # Only if readwrite access was granted
proxy$ bit balance proxy$ bit balance
# Export pending transaction to be signed offline # Export pending transaction to be signed offline

1
bit-wallet/bit-import

@ -9,6 +9,7 @@ program = utils.configureCommander(program);
program program
.version('0.0.1') .version('0.0.1')
.option('-n, --nopasswd [level]', 'Set access for no password usage: none(default), readonly, readwrite, full', 'none')
.usage('import [options] <file>') .usage('import [options] <file>')
.parse(process.argv); .parse(process.argv);

21
bit-wallet/bit-sign

@ -16,11 +16,8 @@ var args = program.args;
var txpid = args[0] || ''; var txpid = args[0] || '';
var client = utils.getClient(program); var client = utils.getClient(program);
client.getTxProposals({}, function(err, txps) {
utils.die(err);
var txp = utils.findOneTxProposal(txps, txpid);
function end(txp) {
if (program.output) { if (program.output) {
client.getSignatures(txp, function(err, signatures) { client.getSignatures(txp, function(err, signatures) {
utils.die(err); utils.die(err);
@ -34,6 +31,7 @@ client.getTxProposals({}, function(err, txps) {
} else { } else {
if (program.input) { if (program.input) {
var infile = JSON.parse(fs.readFileSync(program.input)); var infile = JSON.parse(fs.readFileSync(program.input));
if (infile.id != txp.id) if (infile.id != txp.id)
utils.die('Signatures does not match Transaction') utils.die('Signatures does not match Transaction')
@ -49,4 +47,17 @@ client.getTxProposals({}, function(err, txps) {
console.log('Transaction signed by you.'); console.log('Transaction signed by you.');
}); });
} }
});
};
if (program.input && program.output) {
var inFile = JSON.parse(fs.readFileSync(program.input));
end(inFile.txps[0]);
} else {
client.getTxProposals({}, function(err, txps) {
utils.die(err);
var txp = utils.findOneTxProposal(txps, txpid);
utils.die(err);
end(txp);
});
}

11
bit-wallet/cli-utils.js

@ -6,7 +6,11 @@ var Utils = function() {};
var die = Utils.die = function(err) { var die = Utils.die = function(err) {
if (err) { if (err) {
console.error(err); if (err.code && err.code == 'ECONNREFUSED') {
console.error('Could not connect to Bicore Wallet Service');
} else {
console.error(err);
}
process.exit(1); process.exit(1);
} }
}; };
@ -49,14 +53,19 @@ Utils.getClient = function(args) {
if (args.nopasswd) if (args.nopasswd)
c.setNopasswdAccess(args.nopasswd); c.setNopasswdAccess(args.nopasswd);
var setPassword;
c.on('needPassword', function(cb) { c.on('needPassword', function(cb) {
if (args.password) { if (args.password) {
return cb(args.password); return cb(args.password);
} else { } else {
if (setPassword)
return cb(setPassword);
read({ read({
prompt: 'Password for ' + args.file + ' : ', prompt: 'Password for ' + args.file + ' : ',
silent: true silent: true
}, function(er, password) { }, function(er, password) {
setPassword = password;
return cb(password); return cb(password);
}) })
} }

5
lib/client/api.js

@ -234,6 +234,7 @@ API.prototype.setNopasswdAccess = function(noPasswdAccess) {
API.prototype._processWcdBeforeWrite = function(wcd, cb) { API.prototype._processWcdBeforeWrite = function(wcd, cb) {
var self = this; var self = this;
// Is any encrypted? // Is any encrypted?
if (this.noPasswdAccess == 'full') { if (this.noPasswdAccess == 'full') {
return cb(null, wcd); return cb(null, wcd);
@ -257,6 +258,7 @@ API.prototype._load = function(opts, cb) {
if (err && err.code == 'ENOENT') err = 'NOTFOUND'; if (err && err.code == 'ENOENT') err = 'NOTFOUND';
return cb(err || 'NOTFOUND'); return cb(err || 'NOTFOUND');
} }
self._processWcdAfterRead(rawdata, opts.requiredAccess, cb); self._processWcdAfterRead(rawdata, opts.requiredAccess, cb);
}); });
}; };
@ -618,7 +620,7 @@ API.prototype.export = function(opts, cb) {
if (err) return cb(err); if (err) return cb(err);
var v = []; var v = [];
var myXPubKey = (new Bitcore.HDPublicKey(wcd.xPrivKey)).toString(); var myXPubKey = wcd.xPrivKey ? (new Bitcore.HDPublicKey(wcd.xPrivKey)).toString() : '';
_.each(WALLET_CRITICAL_DATA, function(k) { _.each(WALLET_CRITICAL_DATA, function(k) {
var d; var d;
@ -679,6 +681,7 @@ API.prototype.import = function(str, cb) {
return cb('Invalid source wallet'); return cb('Invalid source wallet');
wcd.network = wcd.publicKeyRing[0].substr(0, 4) == 'tpub' ? 'testnet' : 'livenet'; wcd.network = wcd.publicKeyRing[0].substr(0, 4) == 'tpub' ? 'testnet' : 'livenet';
self.save(wcd, function(err) { self.save(wcd, function(err) {
return cb(err, WalletUtils.accessFromData(wcd)); return cb(err, WalletUtils.accessFromData(wcd));
}); });

2
lib/client/verifier.js

@ -66,6 +66,8 @@ Verifier.checkTxProposal = function(data, txp) {
var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message); var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message);
log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature); log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature);
if (!WalletUtils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) if (!WalletUtils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey))
return false; return false;

4
lib/walletutils.js

@ -185,10 +185,6 @@ WalletUtils.encryptWallet = function(data, accessWithoutEncrytion, password) {
var fieldsEncrypt = fieldsEncryptByLevel[accessWithoutEncrytion]; var fieldsEncrypt = fieldsEncryptByLevel[accessWithoutEncrytion];
$.checkState(!_.isUndefined(fieldsEncrypt)); $.checkState(!_.isUndefined(fieldsEncrypt));
if (!_.every(fieldsEncrypt, function(k) {
return data[k];
})) throw new Error('Wallet does not contain necesary info to encrypt');
var toEncrypt = _.pick(data, fieldsEncrypt); var toEncrypt = _.pick(data, fieldsEncrypt);
var enc = sjcl.encrypt(password, JSON.stringify(toEncrypt), WalletUtils.sjclOpts); var enc = sjcl.encrypt(password, JSON.stringify(toEncrypt), WalletUtils.sjclOpts);

Loading…
Cancel
Save