simplify random.js
This commit is contained in:
parent
3df1d849b3
commit
b088f005da
|
@ -54,7 +54,7 @@ function getPkcs1Padding(length) {
|
||||||
let result = '';
|
let result = '';
|
||||||
let randomByte;
|
let randomByte;
|
||||||
while (result.length < length) {
|
while (result.length < length) {
|
||||||
randomByte = random.getSecureRandomOctet();
|
randomByte = random.getRandomBytes(1)[0];
|
||||||
if (randomByte !== 0) {
|
if (randomByte !== 0) {
|
||||||
result += String.fromCharCode(randomByte);
|
result += String.fromCharCode(randomByte);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,49 +38,7 @@ export default {
|
||||||
* @return {Uint8Array} Random byte array
|
* @return {Uint8Array} Random byte array
|
||||||
*/
|
*/
|
||||||
getRandomBytes: function(length) {
|
getRandomBytes: function(length) {
|
||||||
const result = new Uint8Array(length);
|
const buf = new Uint8Array(length);
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
result[i] = this.getSecureRandomOctet();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a secure random number in the specified range
|
|
||||||
* @param {Integer} from Min of the random number
|
|
||||||
* @param {Integer} to Max of the random number (max 32bit)
|
|
||||||
* @return {Integer} A secure random number
|
|
||||||
*/
|
|
||||||
getSecureRandom: function(from, to) {
|
|
||||||
let randUint = this.getSecureRandomUint();
|
|
||||||
const bits = ((to - from)).toString(2).length;
|
|
||||||
while ((randUint & ((2 ** bits) - 1)) > (to - from)) {
|
|
||||||
randUint = this.getSecureRandomUint();
|
|
||||||
}
|
|
||||||
return from + (Math.abs(randUint & ((2 ** bits) - 1)));
|
|
||||||
},
|
|
||||||
|
|
||||||
getSecureRandomOctet: function() {
|
|
||||||
const buf = new Uint8Array(1);
|
|
||||||
this.getRandomValues(buf);
|
|
||||||
return buf[0];
|
|
||||||
},
|
|
||||||
|
|
||||||
getSecureRandomUint: function() {
|
|
||||||
const buf = new Uint8Array(4);
|
|
||||||
const dv = new DataView(buf.buffer);
|
|
||||||
this.getRandomValues(buf);
|
|
||||||
return dv.getUint32(0);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper routine which calls platform specific crypto random generator
|
|
||||||
* @param {Uint8Array} buf
|
|
||||||
*/
|
|
||||||
getRandomValues: function(buf) {
|
|
||||||
if (!(buf instanceof Uint8Array)) {
|
|
||||||
throw new Error('Invalid type: buf not an Uint8Array');
|
|
||||||
}
|
|
||||||
if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {
|
if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {
|
||||||
window.crypto.getRandomValues(buf);
|
window.crypto.getRandomValues(buf);
|
||||||
} else if (typeof window !== 'undefined' && typeof window.msCrypto === 'object' && typeof window.msCrypto.getRandomValues === 'function') {
|
} else if (typeof window !== 'undefined' && typeof window.msCrypto === 'object' && typeof window.msCrypto.getRandomValues === 'function') {
|
||||||
|
@ -126,15 +84,17 @@ export default {
|
||||||
function RandomBuffer() {
|
function RandomBuffer() {
|
||||||
this.buffer = null;
|
this.buffer = null;
|
||||||
this.size = null;
|
this.size = null;
|
||||||
|
this.callback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize buffer
|
* Initialize buffer
|
||||||
* @param {Integer} size size of buffer
|
* @param {Integer} size size of buffer
|
||||||
*/
|
*/
|
||||||
RandomBuffer.prototype.init = function(size) {
|
RandomBuffer.prototype.init = function(size, callback) {
|
||||||
this.buffer = new Uint8Array(size);
|
this.buffer = new Uint8Array(size);
|
||||||
this.size = 0;
|
this.size = 0;
|
||||||
|
this.callback = callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -79,7 +79,7 @@ SymEncryptedAEADProtected.prototype.decrypt = function (sessionKeyAlgorithm, key
|
||||||
* @return {Promise<undefined>} Nothing is returned
|
* @return {Promise<undefined>} Nothing is returned
|
||||||
*/
|
*/
|
||||||
SymEncryptedAEADProtected.prototype.encrypt = function (sessionKeyAlgorithm, key) {
|
SymEncryptedAEADProtected.prototype.encrypt = function (sessionKeyAlgorithm, key) {
|
||||||
this.iv = crypto.random.getRandomValues(new Uint8Array(IV_LEN)); // generate new random IV
|
this.iv = crypto.random.getRandomBytes(IV_LEN); // generate new random IV
|
||||||
return crypto.gcm.encrypt(sessionKeyAlgorithm, this.packets.write(), key, this.iv).then(encrypted => {
|
return crypto.gcm.encrypt(sessionKeyAlgorithm, this.packets.write(), key, this.iv).then(encrypted => {
|
||||||
this.encrypted = encrypted;
|
this.encrypted = encrypted;
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,7 +20,6 @@ import crypto from '../crypto';
|
||||||
import packet from '../packet';
|
import packet from '../packet';
|
||||||
|
|
||||||
const INITIAL_RANDOM_SEED = 50000; // random bytes seeded to worker
|
const INITIAL_RANDOM_SEED = 50000; // random bytes seeded to worker
|
||||||
const RANDOM_SEED_REQUEST = 20000; // random bytes seeded after worker request
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new proxy and loads the web worker
|
* Initializes a new proxy and loads the web worker
|
||||||
|
@ -75,7 +74,7 @@ AsyncProxy.prototype.onMessage = function(event) {
|
||||||
delete this.tasks[msg.id];
|
delete this.tasks[msg.id];
|
||||||
break;
|
break;
|
||||||
case 'request-seed':
|
case 'request-seed':
|
||||||
this.seedRandom(RANDOM_SEED_REQUEST);
|
this.seedRandom(msg.amount);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown Worker Event.');
|
throw new Error('Unknown Worker Event.');
|
||||||
|
@ -87,24 +86,10 @@ AsyncProxy.prototype.onMessage = function(event) {
|
||||||
* @param {Integer} size Number of bytes to send
|
* @param {Integer} size Number of bytes to send
|
||||||
*/
|
*/
|
||||||
AsyncProxy.prototype.seedRandom = function(size) {
|
AsyncProxy.prototype.seedRandom = function(size) {
|
||||||
const buf = this.getRandomBuffer(size);
|
const buf = crypto.random.getRandomBytes(size);
|
||||||
this.worker.postMessage({ event:'seed-random', buf }, util.getTransferables(buf));
|
this.worker.postMessage({ event:'seed-random', buf }, util.getTransferables(buf));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Uint8Array with random numbers
|
|
||||||
* @param {Integer} size Length of buffer
|
|
||||||
* @return {Uint8Array}
|
|
||||||
*/
|
|
||||||
AsyncProxy.prototype.getRandomBuffer = function(size) {
|
|
||||||
if (!size) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const buf = new Uint8Array(size);
|
|
||||||
crypto.random.getRandomValues(buf);
|
|
||||||
return buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminates the worker
|
* Terminates the worker
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,10 +24,29 @@ self.window = {}; // to make UMD bundles work
|
||||||
importScripts('openpgp.js');
|
importScripts('openpgp.js');
|
||||||
var openpgp = window.openpgp;
|
var openpgp = window.openpgp;
|
||||||
|
|
||||||
|
var randomQueue = [];
|
||||||
|
var randomRequested = false;
|
||||||
var MIN_SIZE_RANDOM_BUFFER = 40000;
|
var MIN_SIZE_RANDOM_BUFFER = 40000;
|
||||||
var MAX_SIZE_RANDOM_BUFFER = 60000;
|
var MAX_SIZE_RANDOM_BUFFER = 60000;
|
||||||
|
var MIN_SIZE_RANDOM_REQUEST = 20000;
|
||||||
|
|
||||||
openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER);
|
/**
|
||||||
|
* Handle random buffer exhaustion by requesting more random bytes from the main window
|
||||||
|
* @return {Promise<Object>} Empty promise whose resolution indicates that the buffer has been refilled
|
||||||
|
*/
|
||||||
|
function randomCallback() {
|
||||||
|
|
||||||
|
if (!randomRequested) {
|
||||||
|
self.postMessage({ event: 'request-seed', amount: MAX_SIZE_RANDOM_BUFFER });
|
||||||
|
}
|
||||||
|
randomRequested = true;
|
||||||
|
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
randomQueue.push(resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openpgp.crypto.random.randomBuffer.init(MAX_SIZE_RANDOM_BUFFER, randomCallback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle messages from the main window.
|
* Handle messages from the main window.
|
||||||
|
@ -43,6 +62,13 @@ self.onmessage = function(event) {
|
||||||
|
|
||||||
case 'seed-random':
|
case 'seed-random':
|
||||||
seedRandom(msg.buf);
|
seedRandom(msg.buf);
|
||||||
|
|
||||||
|
var queueCopy = randomQueue;
|
||||||
|
randomQueue = [];
|
||||||
|
for (var i = 0; i < queueCopy.length; i++) {
|
||||||
|
queueCopy[i]();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -99,8 +125,8 @@ function delegate(id, method, options) {
|
||||||
* @param {Object} event Contains event type and data
|
* @param {Object} event Contains event type and data
|
||||||
*/
|
*/
|
||||||
function response(event) {
|
function response(event) {
|
||||||
if (openpgp.crypto.random.randomBuffer.size < MIN_SIZE_RANDOM_BUFFER) {
|
if (!randomRequested && openpgp.crypto.random.randomBuffer.size < MIN_SIZE_RANDOM_BUFFER) {
|
||||||
self.postMessage({ event: 'request-seed' });
|
self.postMessage({ event: 'request-seed', amount: MIN_SIZE_RANDOM_REQUEST });
|
||||||
}
|
}
|
||||||
self.postMessage(event, openpgp.util.getTransferables(event.data));
|
self.postMessage(event, openpgp.util.getTransferables(event.data));
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,7 +309,7 @@ describe('API functional testing', function() {
|
||||||
if(algo.substr(0,3) === 'aes') {
|
if(algo.substr(0,3) === 'aes') {
|
||||||
it(algo, function() {
|
it(algo, function() {
|
||||||
const key = crypto.generateSessionKey(algo);
|
const key = crypto.generateSessionKey(algo);
|
||||||
const iv = crypto.random.getRandomValues(new Uint8Array(crypto.gcm.ivLength));
|
const iv = crypto.random.getRandomBytes(crypto.gcm.ivLength);
|
||||||
|
|
||||||
return crypto.gcm.encrypt(
|
return crypto.gcm.encrypt(
|
||||||
algo, util.str_to_Uint8Array(plaintext), key, iv
|
algo, util.str_to_Uint8Array(plaintext), key, iv
|
||||||
|
|
Loading…
Reference in New Issue
Block a user