diff --git a/index.js b/index.js index 4c943e9..0b0eef9 100644 --- a/index.js +++ b/index.js @@ -17,6 +17,7 @@ privsec.hash = require('./lib/hash'); privsec.point = require('./lib/point'); privsec.privkey = require('./lib/privkey'); privsec.pubkey = require('./lib/pubkey'); +privsec.random = require('./lib/random'); //privsec.key = require('lib/key'); //privsec.script = require('lib/script'); diff --git a/lib/random.js b/lib/random.js new file mode 100644 index 0000000..eb34636 --- /dev/null +++ b/lib/random.js @@ -0,0 +1,54 @@ +function Random() { +}; + +/* secure random bytes that sometimes throws an error due to lack of entropy */ +Random.getRandomBuffer = function(size) { + if (typeof process === 'undefined' || process.browser) + return Random.getRandomBufferBrowser(size); + else + return Random.getRandomBufferNode(size); +}; + +Random.getRandomBufferNode = function(size) { + var crypto = require('crypto'); + return crypto.randomBytes(size); +} + +Random.getRandomBufferBrowser = function(size) { + if (!window.crypto && !window.msCrypto) + throw new Error('random: window.crypto not available'); + + if (window.crypto && window.crypto.getRandomValues) + var crypto = window.crypto; + else if (window.msCrypto && window.msCrypto.getRandomValues) //internet explorer + var crypto = window.msCrypto; + else + throw new Error('random: window.crypto.getRandomValues not available'); + + var bbuf = new Uint8Array(size); + crypto.getRandomValues(bbuf); + var buf = new Buffer(bbuf); + + return buf; +}; + +/* insecure random bytes, but it never fails */ +Random.getPseudoRandomBuffer = function(size) { + var b32 = 0x100000000; + var b = new Buffer(size); + + for (var i = 0; i <= size; i++) { + var j = Math.floor(i / 4); + var k = i - j * 4; + if (k == 0) { + r = Math.random() * b32; + b[i] = r & 0xff; + } else { + b[i] = (r = r >>> 8) & 0xff; + } + } + + return b; +}; + +module.exports = Random; diff --git a/test/test.random.js b/test/test.random.js new file mode 100644 index 0000000..5c8c3ec --- /dev/null +++ b/test/test.random.js @@ -0,0 +1,61 @@ +var should = require('chai').should(); +var Random = require('../lib/random'); + +describe('Random', function() { + + describe('getRandomBuffer', function() { + + it('should return a buffer', function() { + var bytes = Random.getRandomBuffer(8); + bytes.length.should.equal(8); + Buffer.isBuffer(bytes).should.equal(true); + }); + + it('should not equate two 256 bit random buffers', function() { + var bytes1 = Random.getRandomBuffer(32); + var bytes2 = Random.getRandomBuffer(32); + bytes1.toString('hex').should.not.equal(bytes2.toString('hex')); + }); + + it('should generate 1000 8 byte buffers in a row that are not equal', function() { + var bufs = []; + for (var i = 0; i < 100; i++) + bufs[i] = Random.getRandomBuffer(8); + for (var i = 0; i < 100; i++) + for (var j = i + 1; j < 100; j++) + bufs[i].toString('hex').should.not.equal(bufs[j].toString('hex')); + }); + + }); + + describe('getPseudoRandomBuffer', function() { + + it('should generate 7 random bytes', function() { + var buf = Random.getPseudoRandomBuffer(7); + buf.length.should.equal(7); + }); + + it('should generate 8 random bytes', function() { + var buf = Random.getPseudoRandomBuffer(8); + buf.length.should.equal(8); + }); + + it('should generate 9 random bytes', function() { + var buf = Random.getPseudoRandomBuffer(9); + buf.length.should.equal(9); + }); + + it('should generate 90 random bytes', function() { + var buf = Random.getPseudoRandomBuffer(90); + buf.length.should.equal(90); + }); + + it('should generate two 8 byte buffers that are not equal', function() { + var buf1 = Random.getPseudoRandomBuffer(8); + var buf2 = Random.getPseudoRandomBuffer(8); + buf1.toString('hex').should.not.equal(buf2.toString('hex')); + }); + + }); + +});