Coder Social home page Coder Social logo

bitauth's Introduction

BitAuth

Passwordless authentication using Bitcoin cryptography

Overview

BitAuth is a way to do secure, passwordless authentication using the cryptography in Bitcoin. Instead of using a shared secret, the client signs each request using a private key and the server checks to make sure the signature is valid and matches the public key.

Getting started

Install with Node.js:

npm install bitauth

Advantages over other authentication mechanisms

  • By signing each request, man in the middle attacks are impossible.
  • A nonce is part of the data signed, which prevents replay attacks.
  • The cryptography in Bitcoin is rock solid and is securing billions of dollars worth of bitcoins.
  • It uses elliptic curve cryptography which performs much better than RSA.
  • Because the private key is never revealed to the server, it does not need to be exchanged between the server and client over a side channel like in HMAC.

Technical Overview

BitAuth uses the same technology in Bitcoin. A public private key pair is created using elliptic curve secp256k1. The public SIN (System identification number), like a bitcoin address, is the RIPEMD 160, SHA256 hash of the public key. See https://en.bitcoin.it/wiki/Identity_protocol_v1 for complete details.

In each request, the client includes a nonce to prevent replay attacks. The client signs the full url with the request body concatenated if there is one. The signature is included in the x-signature header and the public key is included in the x-identity header.

The server verifies that the signature is valid and that it matches the identity (the public key). It then computes the SIN from the public key, and sees whether that SIN has access to the requested resource. The nonce is checked to make sure it is higher than the previously used nonce.

Technology is readily available

With the growing popularity of Bitcoin, there are already libraries written in many languages. Because BitAuth uses the same technology as Bitcoin, it is easy to start using BitAuth.

Problems with password authentication

  • Have to keep track of a separate password for every web service. People forget passwords, encouraging them to reuse passwords and opening themselves up to having multiple services compromised.
  • Brute force attacks on weak passwords.
  • Passwords may travel over plaintext
  • Passwords in databases being leaked
  • Phishing attacks to steal passwords

Passwordless based authentication across web services

With BitAuth, users can use the same, strong password to encrypt their keys and not worry about one service gaining access to another.

In the future, an identity system could be built around BitAuth keys where a user could create one key to represent an identity which could authenticate against multiple services.

In order for this to work, there would have to be a browser integration or plugin which would manage these identities and a Javascript API where websites could sign requests going to their website with the private key, but without exposing the private key to the third party sites.

There also needs to be a public place to store SIN's, preferably in a decentralized blockchain or datastore like namecoin. Key revocations could be stored here as well as reviews/feedback to build a reputation around an identity.

Examples

Example server

var express = require('express');
var bodyParser = require('body-parser');
var rawBody = require('../lib/middleware/rawbody');
var bitauth = require('../lib/middleware/bitauth');

var users = {
  'Tf7UNQnxB8SccfoyZScQmb34V2GdEtQkzDz': {name: 'Alice'},
  'Tf22EUFxHWh4wmA3sDuw151W5C5g32jgph2': {name: 'Bob'}
};

var pizzas = [];

var app = express();
app.use(rawBody);
app.use(bodyParser());


app.get('/user', bitauth, function(req, res) {
  if(!req.sin || !users[req.sin]) return res.send(401, {error: 'Unauthorized'});
  res.send(200, users[req.sin]);
});

app.post('/pizzas', bitauth, function(req, res) {
  if(!req.sin || !users[req.sin]) return res.send(401, {error: 'Unauthorized'});
  var pizza = req.body;
  pizza.owner = users[req.sin].name;
  pizzas.push(pizza);
  res.send(200, req.body);
});

app.get('/pizzas', function(req, res) {
  res.send(200, pizzas);
});

app.listen(3000);

Example client

var request = require('request');
var bitauth = require('../lib/bitauth');

// These can be generated with bitauth.generateSin()
var keys = {
  alice: '38f93bdda21a5c4a7bae4eb75bb7811cbc3eb627176805c1009ff2099263c6ad',
  bob: '09880c962437080d72f72c8c63a69efd65d086c9e7851a87b76373eb6ce9aab5'
};

// GET

for(k in keys) {
  var url = 'http://localhost:3000/user';
  var dataToSign = url;
  var options = {
    url: url,
    headers: {
      'x-identity': bitauth.getPublicKeyFromPrivateKey(keys[k]),
      'x-signature': bitauth.sign(dataToSign, keys[k])
    }
  };

  request.get(options, function(err, response, body) {
    if(err) {
      console.log(err);
    }
    if(body) {
      console.log(body);
    }
  });
}

var pizzas = ['pepperoni', 'sausage', 'veggie', 'hawaiian'];

// POST

for(k in keys) {
  var url = 'http://localhost:3000/pizzas';
  var data = {type: pizzas[Math.floor(Math.random() * pizzas.length)]};
  var dataToSign = url + JSON.stringify(data);
  var options = {
    url: url,
    headers: {
      'x-identity': bitauth.getPublicKeyFromPrivateKey(keys[k]),
      'x-signature': bitauth.sign(dataToSign, keys[k])
    },
    json: data
  };

  request.post(options, function(err, response, body) {
    if(err) {
      console.log(err);
    }
    if(body) {
      console.log(body);
    }
  });
}

Middleware

BitAuth exposes a connect middleware for use in connect or ExpressJS applications. Use:

var bitauth = require('bitauth');
app.use( bitauth.middleware );

bitauth's People

Contributors

bitjson avatar braydonf avatar cmgustavo avatar gabrielbazan7 avatar martindale avatar matiu avatar nitsujlangston avatar pnagurny avatar unusualbob avatar xcthulhu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bitauth's Issues

Add encryption

Is there any middleware that adds encryption to this? Signature is nice but I would love all data to be encrypted on the client with the server public key and decrypted on the server with the server private key and vice versa. Would be nice to have another piece of middleware for this. Any plans for this?

signed responses?

Maybe i don't see it in the code, but it looks like that responses are not signed at all?
How would this prevents a MITM to temper a response?

Why not BitID?

There is an existing proposal with working implementations (Darkwallet, Mycelium, mediawiki) . It would be great to give a motivation how BitAuth improves over BitID. This is not clear from the blogpost https://github.com/bitid/bitid

Support non-boolean authentication

A type 1 SIN is associated with a bitcoin sacrifice (See: https://en.bitcoin.it/wiki/Identity_protocol_v1#Creating_sacrifice_transactions). This could enable non-boolean levels authentication. Depending on the amount of bitcoin sacrificed, access can be granted with more granularity.
An example app using this would be a forum where you need to sacrifice 0.01 btc to read, and 0.05 to post. An type 1 SIN which sacrificed 0.05 btc could read and post, and one with a 0.02 sacrifice could only read. Another could be an email server requiring a 0.01*x btc identity for every x emails sent (thus reducing spam). The benefits of adding costs to identity are many, and non-boolean authentication lets apps manage different levels of costs easily.

Tests for Browser

Mocha tests are included to run with Node.js however there isn't an html file to load the tests in a web browser.

Installation error

Trying to install bitauth on a Windows machine and fails with a result
sh scripts/make-dist.sh - si not an executable command or batch file...

In the npm_log at the end I see error:
"953 verbose stack Error: [email protected] postinstall: npm run make-dist
953 verbose stack Exit status 1
953 verbose stack at EventEmitter. (C:\Program "

Invalid character in header content ["x-signature"]

hello
i have a problem when i use this method bitauth.sign() , I put it in the request header i have this error :
" TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["x-signature"]"
any help please thanks
image

why use SIN and not underlying public key?

is it just because the SIN carries an additional few pieces of metadata, such as the SIN type? Or is it for security? As far as I understand the public key is sent with every request, so it's not being kept secret.

one more question: the bitcoin community is very much against reusing private keys, but it seems like SINs are meant to be reused. How do you reconcile the two?

Version 0.3.1 Breaks Google Closure Compiler Support

I'm sorry to report that the latest version has broken the support for the Google Closure Compiler that previous versions provided.

This is a blocker for cljsjs/packages#255 , which is in turn a blocker for getting unicode support into my Clojure(Script) port https://github.com/xcthulhu/clj-bitauth .

I am using the following as my extern file:

var BitAuth = {
    "getPublicKeyFromPrivateKey": function (privateKey) {},
    "getSinFromPublicKey": function (publicKey) {},
    "generateSin": function () {},
    "sign": function (data, privateKey) {},
    "verifySignature": function (data, publicKey, hexSignature, callBack) {},
    "validateSin": function (sin, callBack) {}
};

Perhaps BitPay should host the extern file, since you own the API? At any rate I'm bummed that this doesn't work and I have to resort to the old version without UTF-8 support 😕

Node 0.12.0 has 'bad decrypt' error

Attempting to use bitauth as part of the bitpay node.js module, and seeing

crypto.js:202
  var ret = this._handle.final();
                         ^
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
    at Error (native)
    at Decipher.Cipher.final (crypto.js:202:26)
    at Object.decrypt (/home/.../node_modules/bitauth/lib/decrypt.js:7:23)
    at new Bitpay (/home/.../bitpay.js:53:27)

Has this been encountered yet? Was not having this problem on Node 0.10.33, seems new to 0.12.0

Support encoding to / decoding from mnemonic versions of SINs

Just like electrum provides mnemonic versions of private keys, it would be great if Bitauth could provide this too, directly within the library itself.

This would make memorizing the key much easier for the end user, allowing them to carry their identity with them across devices with minimum friction.

For example, provide two more methods:

bitauth.decodeSinMnemonic(String) -> String - Would take in the mnemonic string as an argument, and output the raw SIN as the return value. This method would be used internally by:

bitauth.getPublicKeyFromPrivateKeyMnemonic(String) -> String - Would take in the mnemonic string as an argument, and output the public key.

I'm not certain at which point the mnemonic should be generated. I considered inside bitauth. generateSin(), but it seems it would be out of place there - thoughts on how you would go about it?

Browser build on Post-Install

Error during installation when bitauth is a dependency:

Building browser bundle for bitauth...
scripts/make-dist.sh: 2: scripts/make-dist.sh: node_modules/.bin/browserify: not found
Minifying bitauth...
scripts/make-dist.sh: 4: scripts/make-dist.sh: node_modules/.bin/uglifyjs: not found
Done!

Bitcore Build Error

When running npm install:

Error: Cannot find module 'sinon' from 'bitauth/node_modules/bitcore'

Implement Hierarchical SINs

Implementing BIP32-style hierarchical SINs would be a fantastic mechanism for creating many identities, but controlled by one individual.

Make A Tagged Release For 0.3.1

Please make a tagged release for 0.3.1

Also, it would help me out over in my CLJSJS package for bitauth if you guys could attach bitauth.bundle.js and bitauth.browser.min.js to the tagged release, since I am clumsily building these payloads right now for the cljsjs/bitauth JAR on clojars, and the CLJSJS maintainers have expressed they would prefer not to do things this way.

Thanks again guys for all of your hard work!

Where is the nonce?

The signed data looks like it is just the url with the params concatenated: https://github.com/bitpay/bitauth/blob/master/examples/client.js#L40

I expect a nonce to be included somewhere so that an attacker is unable to reuse a signature. I'm able to successfully run the following command multiple times against the example server.

curl --header 'x-pubkey: 02d7cfea0841ca90c67f5260013e2fadf86c7fe3587c58851e4489736bb8ed5863' --header 'x-signature: 304502210082b5d01ed62594a66382824236a5932a1ffcdb375a76d7adebbb5a0e803537d90220144c23ac7e576e1be157bc38e595279c18fe214f4a0a728084c0269fd52b5fec' http://localhost:3000/pizzas

𝒰nicode 𝔖upport?

So I have a port of BitAuth to Clojure, and I am trying to work out differences in the implementations.

One basic problem is that JavaScript can't really handle unicode with codepoints above 65535 (see http://stackoverflow.com/q/19354455 for a discussion of this issue).

The solution I have been using elsewhere is to turn strings lists of bytes (or byte-arrays or whatever) using UTF-16 encoding. This works in ClojureScript because the hashing function goog.crypt.sha256 takes lists of bytes, and we always have the Closure libraries around. So the right thing to do might be to swap out hash.js for obvious-closure-library.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.