random number web worker buffer automatic refill
This commit is contained in:
parent
433ae5cce7
commit
572abadc91
src
test
|
@ -37,7 +37,7 @@ export default {
|
|||
* @param {Integer} length Length in bytes to generate
|
||||
* @return {Uint8Array} Random byte array
|
||||
*/
|
||||
getRandomBytes: function(length) {
|
||||
getRandomBytes: async function(length) {
|
||||
const buf = new Uint8Array(length);
|
||||
if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {
|
||||
window.crypto.getRandomValues(buf);
|
||||
|
@ -47,7 +47,7 @@ export default {
|
|||
const bytes = nodeCrypto.randomBytes(buf.length);
|
||||
buf.set(bytes);
|
||||
} else if (this.randomBuffer.buffer) {
|
||||
this.randomBuffer.get(buf);
|
||||
await this.randomBuffer.get(buf);
|
||||
} else {
|
||||
throw new Error('No secure random number generator available.');
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ export default {
|
|||
* @param {module:type/mpi} max Upper bound, excluded
|
||||
* @return {module:BN} Random MPI
|
||||
*/
|
||||
getRandomBN: function(min, max) {
|
||||
getRandomBN: async function(min, max) {
|
||||
if (max.cmp(min) <= 0) {
|
||||
throw new Error('Illegal parameter value: max <= min');
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ export default {
|
|||
// Using a while loop is necessary to avoid bias introduced by the mod operation.
|
||||
// However, we request 64 extra random bits so that the bias is negligible.
|
||||
// Section B.1.1 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
|
||||
const r = new BN(this.getRandomBytes(bytes + 8));
|
||||
const r = new BN(await this.getRandomBytes(bytes + 8));
|
||||
return r.mod(modulus).add(min);
|
||||
},
|
||||
|
||||
|
@ -121,7 +121,7 @@ RandomBuffer.prototype.set = function(buf) {
|
|||
* Take numbers out of buffer and copy to array
|
||||
* @param {Uint8Array} buf the destination array
|
||||
*/
|
||||
RandomBuffer.prototype.get = function(buf) {
|
||||
RandomBuffer.prototype.get = async function(buf) {
|
||||
if (!this.buffer) {
|
||||
throw new Error('RandomBuffer is not initialized');
|
||||
}
|
||||
|
@ -129,7 +129,12 @@ RandomBuffer.prototype.get = function(buf) {
|
|||
throw new Error('Invalid type: buf not an Uint8Array');
|
||||
}
|
||||
if (this.size < buf.length) {
|
||||
throw new Error('Random number buffer depleted');
|
||||
if (!this.callback) {
|
||||
throw new Error('Random number buffer depleted');
|
||||
}
|
||||
// Wait for random bytes from main context, then try again
|
||||
await this.callback();
|
||||
return this.get(buf);
|
||||
}
|
||||
for (let i = 0; i < buf.length; i++) {
|
||||
buf[i] = this.buffer[--this.size];
|
||||
|
|
|
@ -19,8 +19,6 @@ import util from '../util.js';
|
|||
import crypto from '../crypto';
|
||||
import packet from '../packet';
|
||||
|
||||
const INITIAL_RANDOM_SEED = 50000; // random bytes seeded to worker
|
||||
|
||||
/**
|
||||
* Initializes a new proxy and loads the web worker
|
||||
* @constructor
|
||||
|
@ -35,7 +33,6 @@ export default function AsyncProxy({ path='openpgp.worker.js', worker, config }
|
|||
this.worker.onerror = e => {
|
||||
throw new Error('Unhandled error in openpgp worker: ' + e.message + ' (' + e.filename + ':' + e.lineno + ')');
|
||||
};
|
||||
this.seedRandom(INITIAL_RANDOM_SEED);
|
||||
|
||||
if (config) {
|
||||
this.worker.postMessage({ event:'configure', config });
|
||||
|
|
|
@ -278,19 +278,19 @@ describe('API functional testing', function() {
|
|||
});
|
||||
|
||||
function testCFB(plaintext, resync) {
|
||||
symmAlgos.forEach(function(algo) {
|
||||
const symmKey = crypto.generateSessionKey(algo);
|
||||
const symmencData = crypto.cfb.encrypt(crypto.getPrefixRandom(algo), algo, util.str_to_Uint8Array(plaintext), symmKey, resync);
|
||||
symmAlgos.forEach(async function(algo) {
|
||||
const symmKey = await crypto.generateSessionKey(algo);
|
||||
const symmencData = crypto.cfb.encrypt(await crypto.getPrefixRandom(algo), algo, util.str_to_Uint8Array(plaintext), symmKey, resync);
|
||||
const text = util.Uint8Array_to_str(crypto.cfb.decrypt(algo, symmKey, symmencData, resync));
|
||||
expect(text).to.equal(plaintext);
|
||||
});
|
||||
}
|
||||
|
||||
function testAESCFB(plaintext) {
|
||||
symmAlgos.forEach(function(algo) {
|
||||
symmAlgos.forEach(async function(algo) {
|
||||
if(algo.substr(0,3) === 'aes') {
|
||||
const symmKey = crypto.generateSessionKey(algo);
|
||||
const rndm = crypto.getPrefixRandom(algo);
|
||||
const symmKey = await crypto.generateSessionKey(algo);
|
||||
const rndm = await crypto.getPrefixRandom(algo);
|
||||
|
||||
const repeat = new Uint8Array([rndm[rndm.length - 2], rndm[rndm.length - 1]]);
|
||||
const prefix = util.concatUint8Array([rndm, repeat]);
|
||||
|
@ -307,9 +307,9 @@ describe('API functional testing', function() {
|
|||
function testAESGCM(plaintext) {
|
||||
symmAlgos.forEach(function(algo) {
|
||||
if(algo.substr(0,3) === 'aes') {
|
||||
it(algo, function() {
|
||||
const key = crypto.generateSessionKey(algo);
|
||||
const iv = crypto.random.getRandomBytes(crypto.gcm.ivLength);
|
||||
it(algo, async function() {
|
||||
const key = await crypto.generateSessionKey(algo);
|
||||
const iv = await crypto.random.getRandomBytes(crypto.gcm.ivLength);
|
||||
|
||||
return crypto.gcm.encrypt(
|
||||
algo, util.str_to_Uint8Array(plaintext), key, iv
|
||||
|
|
|
@ -12,9 +12,9 @@ describe('Random Buffer', function() {
|
|||
expect(randomBuffer).to.exist;
|
||||
});
|
||||
|
||||
it('Throw error if not initialized', function () {
|
||||
it('Throw error if not initialized', async function () {
|
||||
expect(randomBuffer.set.bind(randomBuffer)).to.throw('RandomBuffer is not initialized');
|
||||
expect(randomBuffer.get.bind(randomBuffer)).to.throw('RandomBuffer is not initialized');
|
||||
await expect(randomBuffer.get(new Uint8Array(1))).to.eventually.be.rejectedWith('RandomBuffer is not initialized');
|
||||
});
|
||||
|
||||
it('Initialization', function () {
|
||||
|
@ -56,13 +56,13 @@ describe('Random Buffer', function() {
|
|||
expect(randomBuffer.size).to.equal(1);
|
||||
});
|
||||
|
||||
it('Get Method', function () {
|
||||
it('Get Method', async function () {
|
||||
randomBuffer.init(5);
|
||||
let buf = new Uint8Array(5);
|
||||
buf[0] = 1; buf[1] = 2; buf[2] = 5; buf[3] = 7; buf[4] = 8;
|
||||
randomBuffer.set(buf);
|
||||
buf = new Uint32Array(2);
|
||||
expect(randomBuffer.get.bind(randomBuffer, buf)).to.throw('Invalid type: buf not an Uint8Array');
|
||||
await expect(randomBuffer.get(buf)).to.eventually.be.rejectedWith('Invalid type: buf not an Uint8Array');
|
||||
buf = new Uint8Array(2);
|
||||
randomBuffer.get(buf);
|
||||
expect(equal(randomBuffer.buffer, [1,2,5,0,0])).to.be.true;
|
||||
|
@ -74,6 +74,6 @@ describe('Random Buffer', function() {
|
|||
expect(buf).to.to.have.property('1', 2);
|
||||
expect(equal(randomBuffer.buffer, [1,0,0,0,0])).to.be.true;
|
||||
expect(randomBuffer.size).to.equal(1);
|
||||
expect(function() { randomBuffer.get(buf); }).to.throw('Random number buffer depleted');
|
||||
await expect(randomBuffer.get(buf)).to.eventually.be.rejectedWith('Random number buffer depleted');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -896,25 +896,6 @@ describe('OpenPGP.js public api tests', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should encrypt then decrypt', function () {
|
||||
const encOpt = {
|
||||
data: plaintext,
|
||||
publicKeys: publicKey.keys
|
||||
};
|
||||
const decOpt = {
|
||||
privateKeys: privateKey.keys
|
||||
};
|
||||
return openpgp.encrypt(encOpt).then(function (encrypted) {
|
||||
expect(encrypted.data).to.match(/^-----BEGIN PGP MESSAGE/);
|
||||
decOpt.message = openpgp.message.readArmored(encrypted.data);
|
||||
return openpgp.decrypt(decOpt);
|
||||
}).then(function (decrypted) {
|
||||
expect(decrypted.data).to.equal(plaintext);
|
||||
expect(decrypted.signatures).to.exist;
|
||||
expect(decrypted.signatures.length).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('should encrypt then decrypt with multiple private keys', function () {
|
||||
const privKeyDE = openpgp.key.readArmored(priv_key_de).keys[0];
|
||||
privKeyDE.decrypt(passphrase);
|
||||
|
@ -1001,9 +982,9 @@ describe('OpenPGP.js public api tests', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should encrypt using custom session key and decrypt using session key', function () {
|
||||
it('should encrypt using custom session key and decrypt using session key', async function () {
|
||||
const sessionKey = {
|
||||
data: openpgp.crypto.generateSessionKey('aes256'),
|
||||
data: await openpgp.crypto.generateSessionKey('aes256'),
|
||||
algorithm: 'aes256'
|
||||
};
|
||||
const encOpt = {
|
||||
|
|
|
@ -47,15 +47,12 @@ tryTests('Async Proxy', tests, {
|
|||
|
||||
function tests() {
|
||||
|
||||
describe('Error handling', function() {
|
||||
it('Depleted random buffer in worker gives error', function() {
|
||||
const wProxy = new openpgp.AsyncProxy({ path:'../dist/openpgp.worker.js' });
|
||||
wProxy.worker = new Worker('../dist/openpgp.worker.js');
|
||||
wProxy.worker.onmessage = wProxy.onMessage.bind(wProxy);
|
||||
wProxy.seedRandom(10);
|
||||
return wProxy.delegate('encrypt', { publicKeys:[pubKey], data:plaintext }).catch(function(err) {
|
||||
expect(err.message).to.match(/Random number buffer depleted/);
|
||||
});
|
||||
describe('Random number pipeline', function() {
|
||||
it('Random number buffer automatically reseeded', function() {
|
||||
const worker = new Worker('../dist/openpgp.worker.js');
|
||||
const wProxy = new openpgp.AsyncProxy({ path:'../dist/openpgp.worker.js', worker });
|
||||
|
||||
return wProxy.delegate('encrypt', { publicKeys:[pubKey], data:plaintext });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user