Web worker: unit tests for random buffer and entropy estimation
This commit is contained in:
parent
c9910929df
commit
a777371418
|
@ -30,11 +30,11 @@ var crypto = require('../crypto'),
|
|||
type_keyid = require('../type/keyid.js'),
|
||||
enums = require('../enums.js');
|
||||
|
||||
var INITIAL_SEED = 4096, // bytes seeded to worker
|
||||
SEED_REQUEST = 4096, // bytes seeded after worker request
|
||||
RSA_FACTOR = 2,
|
||||
DSA_FACTOR = 2,
|
||||
ELG_FACTOR = 2;
|
||||
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)
|
||||
|
||||
/**
|
||||
* Initializes a new proxy and loads the web worker
|
||||
|
@ -106,9 +106,10 @@ AsyncProxy.prototype.entropyEstimation = function(op, publicKeys, privateKeys, o
|
|||
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 && publicKeys.forEach(function(key) {
|
||||
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) {
|
||||
|
@ -120,13 +121,15 @@ AsyncProxy.prototype.entropyEstimation = function(op, publicKeys, privateKeys, o
|
|||
});
|
||||
break;
|
||||
case 'sig':
|
||||
privateKeys && privateKeys.forEach(function(key) {
|
||||
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 keys
|
||||
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;
|
||||
|
@ -166,7 +169,7 @@ 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', publikKeys) +
|
||||
var estimation = this.entropyEstimation('enc', publicKeys) +
|
||||
this.entropyEstimation('sig', null, [privateKey]);
|
||||
publicKeys = publicKeys.map(function(key) {
|
||||
return key.toPacketlist();
|
||||
|
|
|
@ -5,13 +5,8 @@ var openpgp = typeof window != 'undefined' && window.openpgp ? window.openpgp :
|
|||
var chai = require('chai'),
|
||||
expect = chai.expect;
|
||||
|
||||
describe('High level API', function() {
|
||||
|
||||
var proxy;
|
||||
|
||||
this.timeout(0);
|
||||
|
||||
var pub_key_rsa =
|
||||
var pub_key_rsa =
|
||||
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
||||
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
||||
'Type: RSA/RSA',
|
||||
|
@ -37,7 +32,7 @@ describe('High level API', function() {
|
|||
'=h/aX',
|
||||
'-----END PGP PUBLIC KEY BLOCK-----'].join('\n');
|
||||
|
||||
var priv_key_rsa =
|
||||
var priv_key_rsa =
|
||||
['-----BEGIN PGP PRIVATE KEY BLOCK-----',
|
||||
'Version: GnuPG v2.0.19 (GNU/Linux)',
|
||||
'Type: RSA/RSA 1024',
|
||||
|
@ -79,7 +74,7 @@ describe('High level API', function() {
|
|||
'=lw5e',
|
||||
'-----END PGP PRIVATE KEY BLOCK-----'].join('\n');
|
||||
|
||||
var pub_key_de =
|
||||
var pub_key_de =
|
||||
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
|
||||
'Version: GnuPG v2.0.22 (GNU/Linux)',
|
||||
'',
|
||||
|
@ -180,6 +175,12 @@ var priv_key_de =
|
|||
expect(privKeyDE).to.exist;
|
||||
}
|
||||
|
||||
describe('High level API', function() {
|
||||
|
||||
var proxy;
|
||||
|
||||
this.timeout(0);
|
||||
|
||||
before(function() {
|
||||
proxy = new openpgp.AsyncProxy('../dist/openpgp.worker.js');
|
||||
expect(proxy).to.exist;
|
||||
|
@ -271,6 +272,13 @@ var priv_key_de =
|
|||
|
||||
});
|
||||
|
||||
function verifySignature(data, privKey) {
|
||||
expect(data.text).to.equal(plaintext);
|
||||
expect(data.signatures).to.have.length(1);
|
||||
expect(data.signatures[0].valid).to.be.true;
|
||||
expect(data.signatures[0].keyid.equals(privKey.getSigningKeyPacket().getKeyId())).to.be.true;
|
||||
}
|
||||
|
||||
describe('Decrypt and Verify', function() {
|
||||
|
||||
var msgRSA, msgDE;
|
||||
|
@ -286,10 +294,7 @@ var priv_key_de =
|
|||
proxy.decryptAndVerifyMessage(privKeyRSA, [pubKeyRSA], msgRSA, function(err, data) {
|
||||
expect(err).to.not.exist;
|
||||
expect(data).to.exist;
|
||||
expect(data.text).to.equal(plaintext);
|
||||
expect(data.signatures).to.have.length(1);
|
||||
expect(data.signatures[0].valid).to.be.true;
|
||||
expect(data.signatures[0].keyid.equals(privKeyRSA.getSigningKeyPacket().getKeyId())).to.be.true;
|
||||
verifySignature(data, privKeyRSA);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -298,10 +303,28 @@ var priv_key_de =
|
|||
proxy.decryptAndVerifyMessage(privKeyDE, [pubKeyDE], msgDE, function(err, data) {
|
||||
expect(err).to.not.exist;
|
||||
expect(data).to.exist;
|
||||
expect(data.text).to.equal(plaintext);
|
||||
expect(data.signatures).to.have.length(1);
|
||||
expect(data.signatures[0].valid).to.be.true;
|
||||
expect(data.signatures[0].keyid.equals(privKeyDE.getSigningKeyPacket().getKeyId())).to.be.true;
|
||||
verifySignature(data, privKeyDE);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Sign and Encrypt', function() {
|
||||
|
||||
before(function() {
|
||||
privKeyRSA.decrypt('hello world');
|
||||
});
|
||||
|
||||
it('RSA: signAndEncryptMessage async', function (done) {
|
||||
proxy.signAndEncryptMessage([pubKeyRSA], privKeyRSA, plaintext, function(err, data) {
|
||||
expect(err).to.not.exist;
|
||||
expect(data).to.exist;
|
||||
expect(data).to.match(/^-----BEGIN PGP MESSAGE/);
|
||||
var msg = openpgp.message.readArmored(data);
|
||||
expect(msg).to.be.an.instanceof(openpgp.message.Message);
|
||||
var decrypted = openpgp.decryptAndVerifyMessage(privKeyRSA, [pubKeyRSA], msg);
|
||||
verifySignature(decrypted, privKeyRSA);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -337,6 +360,17 @@ var priv_key_de =
|
|||
});
|
||||
});
|
||||
|
||||
it('RSA: verifyClearSignedMessage async', function (done) {
|
||||
var signed = openpgp.signClearMessage([privKeyRSA], plaintext);
|
||||
signed = openpgp.cleartext.readArmored(signed);
|
||||
proxy.verifyClearSignedMessage([pubKeyRSA], signed, function(err, data) {
|
||||
expect(err).to.not.exist;
|
||||
expect(data).to.exist;
|
||||
verifySignature(data, privKeyRSA);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Error handling', function() {
|
||||
|
@ -379,4 +413,125 @@ var priv_key_de =
|
|||
|
||||
});
|
||||
|
||||
describe('Random Buffer', function() {
|
||||
|
||||
var randomBuffer;
|
||||
|
||||
before(function() {
|
||||
randomBuffer = new openpgp.crypto.random.randomBuffer.constructor();
|
||||
expect(randomBuffer).to.exist;
|
||||
});
|
||||
|
||||
it('Throw error if not initialized', function () {
|
||||
expect(randomBuffer.set).to.throw('RandomBuffer is not initialized');
|
||||
expect(randomBuffer.get).to.throw('RandomBuffer is not initialized');
|
||||
});
|
||||
|
||||
it('Initialization', function () {
|
||||
randomBuffer.init(5);
|
||||
expect(randomBuffer.buffer).to.exist;
|
||||
expect(randomBuffer.buffer).to.have.length(5);
|
||||
expect(randomBuffer.size).to.equal(0);
|
||||
});
|
||||
|
||||
function equal(buf, arr) {
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
if (buf[i] !== arr[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
it('Set Method', function () {
|
||||
randomBuffer.init(5);
|
||||
var buf = new Uint32Array(2);
|
||||
buf[0] = 1; buf[1] = 2;
|
||||
randomBuffer.set(buf);
|
||||
expect(equal(randomBuffer.buffer, [1,2,0,0,0])).to.be.true;
|
||||
expect(randomBuffer.size).to.equal(2);
|
||||
randomBuffer.set(buf);
|
||||
expect(equal(randomBuffer.buffer, [1,2,1,2,0])).to.be.true;
|
||||
expect(randomBuffer.size).to.equal(4);
|
||||
randomBuffer.set(buf);
|
||||
expect(equal(randomBuffer.buffer, [1,2,1,2,1])).to.be.true;
|
||||
expect(randomBuffer.size).to.equal(5);
|
||||
randomBuffer.init(1);
|
||||
var buf = new Uint32Array(2);
|
||||
buf[0] = 1; buf[1] = 2;
|
||||
randomBuffer.set(buf);
|
||||
expect(buf).to.to.have.property('0', 1);
|
||||
expect(randomBuffer.size).to.equal(1);
|
||||
});
|
||||
|
||||
it('Get Method', function () {
|
||||
randomBuffer.init(5);
|
||||
var buf = new Uint32Array(5);
|
||||
buf[0] = 1; buf[1] = 2; buf[2] = 5; buf[3] = 7; buf[4] = 8;
|
||||
randomBuffer.set(buf);
|
||||
var buf = new Uint32Array(2);
|
||||
randomBuffer.get(buf);
|
||||
expect(equal(randomBuffer.buffer, [1,2,5,7,8])).to.be.true;
|
||||
expect(randomBuffer.size).to.equal(3);
|
||||
expect(buf).to.to.have.property('0', 8);
|
||||
expect(buf).to.to.have.property('1', 7);
|
||||
expect(equal(randomBuffer.buffer, [1,2,5,7,8])).to.be.true;
|
||||
randomBuffer.get(buf);
|
||||
expect(buf).to.to.have.property('0', 5);
|
||||
expect(buf).to.to.have.property('1', 2);
|
||||
expect(randomBuffer.size).to.equal(1);
|
||||
expect(function() { randomBuffer.get(buf) }).to.throw('Random number buffer depleted.');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user