Browse Source

replace jsbn's rng with module secure-random

This uses window.crypto.getRandomValues on browser
and crypto.randomBytes on node
hk-custom-address
Wei Lu 11 years ago
parent
commit
b7861e4336
  1. 3
      package.json
  2. 3
      src/ecdsa.js
  3. 6
      src/jsbn/jsbn.js
  4. 39
      src/jsbn/prng4.js
  5. 85
      src/jsbn/rng.js
  6. 8
      src/wallet.js
  7. 9
      test/jsbn.js
  8. 6
      test/misc.js

3
package.json

@ -40,6 +40,7 @@
"compile": "./node_modules/.bin/browserify ./src/index.js -s Bitcoin | ./node_modules/.bin/uglifyjs > bitcoinjs-min.js"
},
"dependencies": {
"crypto-js": "3.1.2-2"
"crypto-js": "3.1.2-2",
"secure-random": "^0.2.0"
}
}

3
src/ecdsa.js

@ -1,12 +1,11 @@
var sec = require('./jsbn/sec');
var SecureRandom = require('./jsbn/rng');
var rng = require('secure-random');
var BigInteger = require('./jsbn/jsbn');
var convert = require('./convert')
var HmacSHA256 = require('crypto-js/hmac-sha256');
var ECPointFp = require('./jsbn/ec').ECPointFp;
var rng = new SecureRandom();
var ecparams = sec("secp256k1");
var P_OVER_FOUR = null;

6
src/jsbn/jsbn.js

@ -672,9 +672,9 @@ function bnpFromNumber(a,b,c) {
}
else {
// new BigInteger(int,RNG)
var x = new Array(), t = a&7;
x.length = (a>>3)+1;
b.nextBytes(x);
var t = a&7;
var length = (a>>3)+1;
var x = b(length, {array: true});
if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
self.fromString(x,256);
}

39
src/jsbn/prng4.js

@ -1,39 +0,0 @@
// prng4.js - uses Arcfour as a PRNG
function Arcfour() {
this.i = 0;
this.j = 0;
this.S = new Array();
}
// Initialize arcfour context from key, an array of ints, each from [0..255]
function ARC4init(key) {
var i, j, t;
for(i = 0; i < 256; ++i)
this.S[i] = i;
j = 0;
for(i = 0; i < 256; ++i) {
j = (j + this.S[i] + key[i % key.length]) & 255;
t = this.S[i];
this.S[i] = this.S[j];
this.S[j] = t;
}
this.i = 0;
this.j = 0;
}
function ARC4next() {
var t;
this.i = (this.i + 1) & 255;
this.j = (this.j + this.S[this.i]) & 255;
t = this.S[this.i];
this.S[this.i] = this.S[this.j];
this.S[this.j] = t;
return this.S[(t + this.S[this.i]) & 255];
}
Arcfour.prototype.init = ARC4init;
Arcfour.prototype.next = ARC4next;
module.exports = Arcfour;

85
src/jsbn/rng.js

@ -1,85 +0,0 @@
// Random number generator - requires a PRNG backend, e.g. prng4.js
// prng4.js - uses Arcfour as a PRNG
var Arcfour = require('./prng4');
// Plug in your RNG constructor here
function prng_newstate() {
return new Arcfour();
}
// Pool size must be a multiple of 4 and greater than 32.
// An array of bytes the size of the pool will be passed to init()
var rng_psize = 256;
// For best results, put code like
// <body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'>
// in your main HTML document.
var rng_state;
var rng_pool;
var rng_pptr;
// Mix in a 32-bit integer into the pool
function rng_seed_int(x) {
rng_pool[rng_pptr++] ^= x & 255;
rng_pool[rng_pptr++] ^= (x >> 8) & 255;
rng_pool[rng_pptr++] ^= (x >> 16) & 255;
rng_pool[rng_pptr++] ^= (x >> 24) & 255;
if(rng_pptr >= rng_psize) rng_pptr -= rng_psize;
}
// Mix in the current time (w/milliseconds) into the pool
function rng_seed_time() {
rng_seed_int(new Date().getTime());
}
// Initialize the pool with junk if needed.
if(rng_pool == null) {
rng_pool = new Array();
rng_pptr = 0;
var t;
// TODO(shtylman) use browser crypto if available
/*
if(navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto) {
// Extract entropy (256 bits) from NS4 RNG if available
var z = window.crypto.random(32);
for(t = 0; t < z.length; ++t)
rng_pool[rng_pptr++] = z.charCodeAt(t) & 255;
}
*/
while(rng_pptr < rng_psize) { // extract some randomness from Math.random()
t = Math.floor(65536 * Math.random());
rng_pool[rng_pptr++] = t >>> 8;
rng_pool[rng_pptr++] = t & 255;
}
rng_pptr = 0;
rng_seed_time();
//rng_seed_int(window.screenX);
//rng_seed_int(window.screenY);
}
function rng_get_byte() {
if(rng_state == null) {
rng_seed_time();
rng_state = prng_newstate();
rng_state.init(rng_pool);
for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr)
rng_pool[rng_pptr] = 0;
rng_pptr = 0;
//rng_pool = null;
}
// TODO: allow reseeding after first request
return rng_state.next();
}
function rng_get_bytes(ba) {
var i;
for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte();
}
function SecureRandom() {}
SecureRandom.prototype.nextBytes = rng_get_bytes;
module.exports = SecureRandom;

8
src/wallet.js

@ -7,8 +7,7 @@ var Transaction = require('./transaction').Transaction;
var TransactionIn = require('./transaction').TransactionIn;
var TransactionOut = require('./transaction').TransactionOut;
var HDNode = require('./hdwallet.js')
var SecureRandom = require('./jsbn/rng');
var rng = new SecureRandom();
var rng = require('secure-random');
var Wallet = function (seed, options) {
if (!(this instanceof Wallet)) { return new Wallet(seed, options); }
@ -32,10 +31,7 @@ var Wallet = function (seed, options) {
// Make a new master key
this.newMasterKey = function(seed, network) {
if (!seed) {
var seed= new Array(32);
rng.nextBytes(seed);
}
if (!seed) seed= rng(32, { array: true })
masterkey = new HDNode(seed, network);
// HD first-level child derivation method should be private

9
test/jsbn.js

@ -2,6 +2,7 @@
var assert = require('assert');
var BigInteger = require('../src/jsbn/jsbn.js')
var bytesToHex = require('../src/convert.js').bytesToHex;
var secureRandom = require('secure-random');
describe('BigInteger', function() {
describe('toByteArraySigned', function() {
@ -25,4 +26,12 @@ describe('BigInteger', function() {
assert.equal(hex(-62300), '0x80f35c');
})
})
describe('with RNG passed into constructor as the 2nd argument', function(){
it('returns a BigInteger with the limit of the specified length', function(){
var bitLength = 256
var i = new BigInteger(bitLength, secureRandom)
assert(i.bitLength() <= 256)
})
})
})

6
test/misc.js

@ -1,13 +1,9 @@
/* global it */
var assert = require('assert');
var bitcoinjs = require('../');
var sec = require('../src/jsbn/sec');
var BigInteger = require('../src/jsbn/jsbn.js');
var SHA256 = require('crypto-js/sha256');
var SecureRandom = require('../src/jsbn/rng');
var rng = new SecureRandom();
var rng = require('secure-random');
var ecparams = sec('secp256k1');
var ECPointFp = bitcoinjs.ECPointFp;
var convert = require('../src/convert');

Loading…
Cancel
Save