diff --git a/src/worker/async_proxy.js b/src/worker/async_proxy.js index 2b44880e..e5235644 100644 --- a/src/worker/async_proxy.js +++ b/src/worker/async_proxy.js @@ -30,11 +30,8 @@ var crypto = require('../crypto'), type_keyid = require('../type/keyid.js'), enums = require('../enums.js'); -var INITIAL_SEED = 4096, // random bytes seeded to worker - SEED_REQUEST = 4096, // random bytes seeded after worker request - RSA_FACTOR = 2, // estimated rounds required to find BigInt for p + rounds required to find BigInt for q - DSA_FACTOR = 2 // estimated rounds required in random.getRandomBigIntegerInRange(2, q-1) - ELG_FACTOR = 2; // estimated rounds required in random.getRandomBigIntegerInRange(2, p-2) +var INITIAL_RANDOM_SEED = 50000, // random bytes seeded to worker + RANDOM_SEED_REQUEST = 20000; // random bytes seeded after worker request /** * Initializes a new proxy and loads the web worker @@ -44,7 +41,7 @@ var INITIAL_SEED = 4096, // random bytes seeded to worker function AsyncProxy(path) { this.worker = new Worker(path || 'openpgp.worker.js'); this.worker.onmessage = this.onMessage.bind(this); - this.seedRandom(INITIAL_SEED); + this.seedRandom(INITIAL_RANDOM_SEED); // FIFO this.tasks = []; } @@ -59,7 +56,7 @@ AsyncProxy.prototype.onMessage = function(event) { this.tasks.shift()(msg.err ? new Error(msg.err) : null, msg.data); break; case 'request-seed': - this.seedRandom(SEED_REQUEST); + this.seedRandom(RANDOM_SEED_REQUEST); break; default: throw new Error('Unknown Worker Event.'); @@ -94,53 +91,6 @@ AsyncProxy.prototype.terminate = function() { this.worker.terminate(); }; -/** - * Estimation on how much random bytes are required to process the operation - * @param {String} op 'enc', 'sig' or 'gen' - * @param {Array} publicKeys - * @param {Array} privateKeys - * @param {Object} options - * @return {Integer} number of bytes required - */ -AsyncProxy.prototype.entropyEstimation = function(op, publicKeys, privateKeys, options) { - var requ = 0; // required entropy in bytes - switch (op) { - case 'enc': - if (!publicKeys) throw new Error('publicKeys required for operation enc'); - requ += 32; // max. size of session key - requ += 16; // max. size CFB prefix random - publicKeys.forEach(function(key) { - var subKeyPackets = key.getSubkeyPackets(); - for (var i = 0; i < subKeyPackets.length; i++) { - if (enums.write(enums.publicKey, subKeyPackets[i].algorithm) == enums.publicKey.elgamal) { - var keyByteSize = subKeyPackets[i].mpi[0].byteLength(); - requ += keyByteSize * ELG_FACTOR; // key byte size for ElGamal keys - break; - } - } - }); - break; - case 'sig': - if (!privateKeys) throw new Error('privateKeys required for operation sig'); - privateKeys.forEach(function(key) { - if (enums.write(enums.publicKey, key.primaryKey.algorithm) == enums.publicKey.dsa) { - requ += 32 * DSA_FACTOR; // 32 bytes for DSA N value - } - }); - break; - case 'gen': - if (!options.numBits) throw new Error('options.numBits required for operation gen'); - requ += 8; // salt for S2K; - requ += 16; // CFB initialization vector - requ += (Math.ceil(options.numBits / 8) + 1) * RSA_FACTOR; - requ = requ * 2; // * number of key packets - break; - default: - throw new Error('Unknown operation.'); - } - return requ; -}; - /** * Encrypts message text with keys * @param {Array} keys array of keys, used to encrypt the message @@ -148,15 +98,13 @@ AsyncProxy.prototype.entropyEstimation = function(op, publicKeys, privateKeys, o * @param {Function} callback receives encrypted ASCII armored message */ AsyncProxy.prototype.encryptMessage = function(keys, text, callback) { - var estimation = this.entropyEstimation('enc', keys); keys = keys.map(function(key) { return key.toPacketlist(); }); this.worker.postMessage({ event: 'encrypt-message', keys: keys, - text: text, - seed: this.getRandomBuffer(estimation) + text: text }); this.tasks.push(callback); }; @@ -169,8 +117,6 @@ AsyncProxy.prototype.encryptMessage = function(keys, text, callback) { * @param {Function} callback receives encrypted ASCII armored message */ AsyncProxy.prototype.signAndEncryptMessage = function(publicKeys, privateKey, text, callback) { - var estimation = this.entropyEstimation('enc', publicKeys) + - this.entropyEstimation('sig', null, [privateKey]); publicKeys = publicKeys.map(function(key) { return key.toPacketlist(); }); @@ -179,8 +125,7 @@ AsyncProxy.prototype.signAndEncryptMessage = function(publicKeys, privateKey, te event: 'sign-and-encrypt-message', publicKeys: publicKeys, privateKey: privateKey, - text: text, - seed: this.getRandomBuffer(estimation) + text: text }); this.tasks.push(callback); }; @@ -239,15 +184,13 @@ AsyncProxy.prototype.decryptAndVerifyMessage = function(privateKey, publicKeys, * @param {Function} callback receives ASCII armored message */ AsyncProxy.prototype.signClearMessage = function(privateKeys, text, callback) { - var estimation = this.entropyEstimation('sig', null, privateKeys); privateKeys = privateKeys.map(function(key) { return key.toPacketlist(); }); this.worker.postMessage({ event: 'sign-clear-message', privateKeys: privateKeys, - text: text, - seed: this.getRandomBuffer(estimation) + text: text }); this.tasks.push(callback); }; @@ -294,8 +237,7 @@ AsyncProxy.prototype.generateKeyPair = function(keyType, numBits, userId, passph keyType: keyType, numBits: numBits, userId: userId, - passphrase: passphrase, - seed: this.getRandomBuffer(this.entropyEstimation('gen', null, null, {numBits: numBits})) + passphrase: passphrase }); this.tasks.push(function(err, data) { if (data) { diff --git a/src/worker/worker.js b/src/worker/worker.js index 2938ec3a..f8d6a2ef 100644 --- a/src/worker/worker.js +++ b/src/worker/worker.js @@ -19,8 +19,8 @@ window = {}; // to make UMD bundles work importScripts('openpgp.js'); -var MIN_SIZE_RANDOM_BUFFER = 8192; -var MAX_SIZE_RANDOM_BUFFER = 16384; +var MIN_SIZE_RANDOM_BUFFER = 40000; +var MAX_SIZE_RANDOM_BUFFER = 60000; window.openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER); @@ -29,9 +29,6 @@ onmessage = function (event) { err = null, msg = event.data, correct = false; - if (msg.seed) { - window.openpgp.crypto.random.randomBuffer.set(msg.seed); - } switch (msg.event) { case 'seed-random': window.openpgp.crypto.random.randomBuffer.set(msg.buf); diff --git a/test/worker/api.js b/test/worker/api.js index 30e764e5..0edc0596 100644 --- a/test/worker/api.js +++ b/test/worker/api.js @@ -386,6 +386,19 @@ describe('High level API', function() { }); }); + it('Depleted random buffer in worker gives error', function (done) { + var wProxy = new openpgp.AsyncProxy('../dist/openpgp.worker.js'); + wProxy.worker = new Worker('../dist/openpgp.worker.js'); + wProxy.worker.onmessage = wProxy.onMessage.bind(wProxy); + wProxy.seedRandom(10); + wProxy.encryptMessage([pubKeyRSA], plaintext, function(err, data) { + expect(data).to.not.exist; + expect(err).to.exist; + expect(err).to.eql(new Error('Random number buffer depleted.')); + done(); + }); + }); + }); describe('Key generation', function() { @@ -539,56 +552,3 @@ describe('Random Buffer', function() { }); }); - -describe('Entropy Estimation', function() { - - var proxy; - - before(function() { - proxy = new openpgp.AsyncProxy('../dist/openpgp.worker.js'); - expect(proxy).to.exist; - initKeys(); - }); - - it('RSA encrypt', function () { - var oneRSA = proxy.entropyEstimation('enc', [pubKeyRSA]); - // 32 byte session key + 16 byte CFB prefix - expect(oneRSA).to.equal(48); - var twoRSA = proxy.entropyEstimation('enc', [pubKeyRSA, pubKeyRSA]); - // only number of symmetrically encrypted packets relevant (we expect 1) - expect(twoRSA).to.equal(oneRSA); - }); - - it('RSA sign', function () { - var oneRSA = proxy.entropyEstimation('sig', null, [privKeyRSA]); - // no entropy required for RSA signing - expect(oneRSA).to.equal(0); - }); - - it('RSA generate', function () { - var oneRSA = proxy.entropyEstimation('gen', null, null, {numBits: 2048}); - // 8 salt for S2K - // 16 CFB initialization vector - // 256 byte size of key - // 1 ? - // 2 at least one round required for p and one for and q required - // 2 number of key packets - expect(oneRSA).to.equal((8 + 16 + (256 + 1) * 2) * 2); - }); - - it('ELG encrypt', function () { - var oneELG = proxy.entropyEstimation('enc', [pubKeyDE]); - // 32 byte session key + 16 byte CFB prefix - // 2 estimated rounds required in random.getRandomBigIntegerInRange(2, p-2) - expect(oneELG).to.equal(48 + (pubKeyDE.subKeys[0].subKey.getBitSize() / 8) * 2); - - }); - - it('DSA sign', function () { - var oneDSA = proxy.entropyEstimation('sig', null, [privKeyDE]); - // 32 bytes for DSA N value - // 2 estimated rounds required in random.getRandomBigIntegerInRange(2, q-1) - expect(oneDSA).to.equal(32 * 2); - }); - -});