2016-07-27 09:53:40 +03:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var aes = require('aes-js');
|
|
|
|
var randomBytes = require('./random-bytes.js');
|
|
|
|
|
2016-07-23 10:27:14 +03:00
|
|
|
var utils = require('./utils.js');
|
|
|
|
|
|
|
|
function Randomish() {
|
2016-07-27 09:53:40 +03:00
|
|
|
if (!(this instanceof Randomish)) { throw new Error('missing new'); }
|
|
|
|
|
2016-07-27 10:02:30 +03:00
|
|
|
var weak = (randomBytes._weakCrypto || false);
|
|
|
|
|
|
|
|
var entropyBits = (weak ? 0: ((32 + 16) * 8));
|
2016-07-27 09:53:40 +03:00
|
|
|
Object.defineProperty(this, 'entropy', {
|
|
|
|
enumerable: true,
|
2016-07-27 10:02:30 +03:00
|
|
|
get: function() { return entropyBits; }
|
2016-07-27 09:53:40 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
var entropy = new aes.ModeOfOperation.cbc(
|
|
|
|
Randomish.randomishBytes(32),
|
|
|
|
Randomish.randomishBytes(16)
|
|
|
|
);
|
|
|
|
|
2016-07-27 10:02:30 +03:00
|
|
|
utils.defineProperty(this, 'feedEntropy', function(data, expectedEntropyBits) {
|
2016-07-27 09:53:40 +03:00
|
|
|
if (!data) { data = ''; }
|
2016-07-27 10:02:30 +03:00
|
|
|
if (!expectedEntropyBits) { expectedEntropyBits = 0; }
|
2016-07-27 09:53:40 +03:00
|
|
|
|
2016-07-27 10:09:11 +03:00
|
|
|
if (parseInt(expectedEntropyBits) != expectedEntropyBits) {
|
|
|
|
throw new Error('invalid expectedEntropyBits');
|
2016-07-27 10:02:30 +03:00
|
|
|
}
|
2016-07-27 09:53:40 +03:00
|
|
|
|
|
|
|
data = (new Date()).getTime() + '-' + JSON.stringify(data) + '-' + data.toString();
|
|
|
|
var hashed = utils.sha3(new Buffer(data, 'utf8'));
|
|
|
|
|
2016-07-27 10:02:30 +03:00
|
|
|
entropyBits += expectedEntropyBits + (weak ? 0: ((32) * 8));
|
2016-07-27 09:53:40 +03:00
|
|
|
|
|
|
|
// Feed the hashed data and random data to the mode of operation
|
|
|
|
entropy.encrypt(hashed.slice(0, 16));
|
|
|
|
entropy.encrypt(randomBytes(16));
|
|
|
|
entropy.encrypt(hashed.slice(0, 16));
|
|
|
|
return new Buffer(entropy.encrypt(randomBytes(16)));
|
|
|
|
});
|
|
|
|
|
|
|
|
utils.defineProperty(this, 'randomBytes', function(length, key) {
|
|
|
|
if (parseInt(length) != length || length <= 0 || length > 1024) {
|
|
|
|
throw new Error('invalid length');
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't have a key, create one
|
|
|
|
if (!key) {
|
|
|
|
key = Buffer.concat([this.feedEntropy(), this.feedEntropy()]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Buffer.isBuffer(key) || key.length !== 32) {
|
|
|
|
throw new Error('invalid key');
|
|
|
|
}
|
|
|
|
|
|
|
|
var aesCbc = new aes.ModeOfOperation.cbc(key, this.feedEntropy());
|
|
|
|
var result = new Buffer(0);
|
|
|
|
while (result.length < length) {
|
2016-08-07 22:17:53 +03:00
|
|
|
result = Buffer.concat([result, this.feedEntropy()]);
|
2016-07-27 09:53:40 +03:00
|
|
|
}
|
|
|
|
|
2016-08-07 22:17:53 +03:00
|
|
|
return result.slice(0, length);
|
2016-07-27 09:53:40 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
this.feedEntropy();
|
2016-07-23 10:27:14 +03:00
|
|
|
}
|
|
|
|
|
2016-07-27 09:53:40 +03:00
|
|
|
utils.defineProperty(Randomish, 'randomishBytes', function(length) {
|
|
|
|
return randomBytes(length);
|
2016-07-23 10:27:14 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
module.exports = Randomish
|