diff --git a/readme.md b/readme.md index 93bb89f..fea258b 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,11 @@ Ethereum authentication ======================= -This project contains a first draft version of a authentication and authorizaion service in blockchain technolgy. The sevice provides a library which helps setting \ No newline at end of file +This project contains a first draft version of a authentication and authorizaion service in blockchain technolgy. The sevice provides a library with a set of solidity contracts which together form a authorization service. + +Text from hackaton +------------------ +From 2018 onwards banks must grant third party apps access to client information. For example, the application where you manage your payments does not have to be from your own bank. Allowing third party applications to interact with this data will drive innovation. However, banks will still be held accountable for the security and integrity of client information. We believe the best way to guarantee client security is using blockchain technology. +Currently, banks provide proprietary apps and an internal API to their customers. For example ING Mobile Pay. An API functions as a gateway to the banks information. Whenever you check your current balance with your banking app, the app will send a structured message to the API. In return the API replies in a structured manner. +Banks will have to open up their API’s to third party providers. However, banks will not know what happens beyond the API. Did the customer give permission for a transaction, or not? Did the customer give permission for companies to use this data, or not? In order to tackle this issue we add blockchain technology to the system. A bank account is linked to a blockchain contract where the accountholder signs messages with a private key. Using this contract the accountholder authorizes an individual or company. Subsequently this contract can be used to obtain account information or initiate payments on his behalf. +The advantage of using a decentralized and public blockchain over a traditional database within the bank is the resilient nature of the blockchain. Moreover, the creation of new blocks based on the previous chain hardens the data and makes the information it holds irrefutable. Harnessing blockchain technology presents the next generation in omnichannel payments where the customer is in control. diff --git a/src/contracts.js b/src/contracts.js index 8286e54..ddcafed 100644 --- a/src/contracts.js +++ b/src/contracts.js @@ -8,7 +8,8 @@ require.extensions['.sol'] = function (module, filename) { var contracts = { app: require('./contracts/App.sol'), user: require('./contracts/User.sol'), - grant: require('./contracts/Grant.sol') + grant: require('./contracts/Grant.sol'), + passwordDelegate: require('./contracts/PasswordDelegate.sol') }; var all = "" diff --git a/src/contracts/PasswordDelegate.sol b/src/contracts/PasswordDelegate.sol index ba5a210..a43dcfc 100644 --- a/src/contracts/PasswordDelegate.sol +++ b/src/contracts/PasswordDelegate.sol @@ -1,23 +1,20 @@ contract PasswordDelegate{ - address private user; + address user; - bytes32 private challenge; - bytes32 private response; + bytes32 challenge; + bytes24 response; - - function PasswordDelegate(address _user, bytes32 _challenge, bytes32 _response){ - user = _user; + function PasswordDelegate(bytes32 _challenge, bytes24 _response){ challenge = _challenge; response = _response; } - function challenge() constant returns(bytes32 challenge){ + function getChallenge() constant returns(bytes32){ return challenge; } - function response(bytes32 _response, address grant ){ - if(response != _response) throw; - User(user).authorize(grant); + function authorize(uint8 v, bytes32 r, bytes32 s ) constant returns(address){ + return ecrecover(challenge, v, r, s); } } \ No newline at end of file diff --git a/test/PasswordDelegate.spec.js b/test/PasswordDelegate.spec.js new file mode 100644 index 0000000..b789711 --- /dev/null +++ b/test/PasswordDelegate.spec.js @@ -0,0 +1,146 @@ +var assert = require('assert'); + +var Web3 = require('web3'); +var ethereumjsUtil = require('ethereumjs-util'); + +var secp256k1 = require('secp256k1'); +var crypto = require('crypto'); + +var Watch = require('../src/watch'); +var Wallet = require('../src/wallet'); + +var contracts = require('../src/contracts'); + +describe('PasswordDelegate', function () { + + this.timeout(1000000); + + var DEFAULT_GAS = 50000000000000; + + var web3 = new Web3(); + var watch = new Watch(web3); + + var defaultProvider = new web3.providers.HttpProvider("http://128.199.53.68:8545") + + web3.setProvider(defaultProvider); + web3.eth.defaultAccount = web3.eth.coinbase; + + var compiled = web3.eth.compile.solidity(contracts); + + var wallet; + var passwordDelegateContract; + + var password = new Buffer(web3.sha3('wilm123456')); + + var challenge; + var response; + + var privateKey; + + var signature = {}; + + function createPrivateKey(challenge, password) { + return Buffer.concat([ + password.slice(0, 8), + challenge.slice(8, 16), + password.slice(24, 32), + challenge.slice(16, 24) + ]); + + } + + it('should create create chalange', function (done) { + + challenge = crypto.randomBytes(32); + console.log('challenge:', challenge.toString('hex')); + + var privateKey = createPrivateKey(challenge, password); + console.log('privateKey:', privateKey.toString('hex')); + + response = ethereumjsUtil.privateToAddress(privateKey); + console.log('response:', response.toString('hex')); + + + var sign = secp256k1.sign(challenge, privateKey); + + signature.r = sign.signature.slice(0, 32); + signature.s = sign.signature.slice(32, 64); + signature.v = sign.recovery + 27; + + console.log(signature); + + var recover = secp256k1.recover(challenge, new Buffer(sign.signature, 'hex'), sign.recovery); + + console.log(response); + console.log(recover); + + done(); + + }); + + it('should create a app wallet and transfer 1 ether', function (done) { + + wallet = new Wallet(); + var transaction = web3.eth.sendTransaction({ + from: web3.eth.coinbase, + to: wallet.address, + value: web3.toWei(1, "ether") + } + ); + + watch(transaction, function (err, res) { + console.log(err, res); + done(); + }) + + }); + + it('should create passwordDelegate contract by wallet', function (done) { + + var abi = compiled.PasswordDelegate.info.abiDefinition; + var code = compiled.PasswordDelegate.code; + + console.log('challenge:', challenge.toString('hex')); + + wallet.eth.contract(abi).new('0x' + challenge.toString('hex'), '0x' + response.toString('hex'), { + gas: DEFAULT_GAS, + data: code + }, callback); + + function callback(err, contract) { + if (err) { + console.log("Contract creation error", err); + done(err); + } else if (contract.address) { + console.log("passwordDelegateContract:", contract.address); + passwordDelegateContract = contract; + done(); + } + }; + }); + + it('should execute challenge response', function (done) { + + var lala = passwordDelegateContract.getChallenge(); + console.log('lala:', lala); + + var challenge = new Buffer(passwordDelegateContract.getChallenge().slice(2), 'hex'); + console.log('challenge:', challenge.toString('hex')); + + var privateKey = createPrivateKey(challenge, password); + var sign = secp256k1.sign(challenge, privateKey); + + var v = sign.recovery + 27; + var r = sign.signature.slice(0, 32); + var s = sign.signature.slice(32, 64); + + console.log(v,r,s); + + var validate = passwordDelegateContract.authorize(v, '0x' + r.toString('hex'), '0x' + s.toString('hex')); + console.log("validate:", validate); + + assert.equal('0x' + response.toString('hex'), validate); + + done(); + }); +}); \ No newline at end of file