Deduplicate getPreferredSymAlgo / getPreferredAEADAlgo

This commit is contained in:
Daniel Huigens 2018-04-20 18:09:54 +02:00
parent 4568d080d5
commit 0376f49e01
3 changed files with 42 additions and 56 deletions

View File

@ -1436,31 +1436,34 @@ export async function getPreferredHashAlgo(key, date) {
} }
/** /**
* Returns the preferred symmetric algorithm for a set of keys * Returns the preferred symmetric/aead algorithm for a set of keys
* @param {symmetric|aead} type Type of preference to return
* @param {Array<module:key.Key>} keys Set of keys * @param {Array<module:key.Key>} keys Set of keys
* @param {Date} date (optional) use the given date for verification instead of the current time * @param {Date} date (optional) use the given date for verification instead of the current time
* @returns {Promise<module:enums.symmetric>} Preferred symmetric algorithm * @returns {Promise<module:enums.symmetric>} Preferred symmetric algorithm
* @async * @async
*/ */
export async function getPreferredSymAlgo(keys, date) { export async function getPreferredAlgo(type, keys, date) {
const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms';
const defaultAlgo = type === 'symmetric' ? config.encryption_cipher : config.aead_mode;
const prioMap = {}; const prioMap = {};
await Promise.all(keys.map(async function(key) { await Promise.all(keys.map(async function(key) {
const primaryUser = await key.getPrimaryUser(date); const primaryUser = await key.getPrimaryUser(date);
if (!primaryUser || !primaryUser.selfCertification.preferredSymmetricAlgorithms) { if (!primaryUser || !primaryUser.selfCertification[prefProperty]) {
return config.encryption_cipher; return defaultAlgo;
} }
primaryUser.selfCertification.preferredSymmetricAlgorithms.forEach(function(algo, index) { primaryUser.selfCertification[prefProperty].forEach(function(algo, index) {
const entry = prioMap[algo] || (prioMap[algo] = { prio: 0, count: 0, algo: algo }); const entry = prioMap[algo] || (prioMap[algo] = { prio: 0, count: 0, algo: algo });
entry.prio += 64 >> index; entry.prio += 64 >> index;
entry.count++; entry.count++;
}); });
})); }));
let prefAlgo = { prio: 0, algo: config.encryption_cipher }; let prefAlgo = { prio: 0, algo: defaultAlgo };
for (const algo in prioMap) { for (const algo in prioMap) {
try { try {
if (algo !== enums.symmetric.plaintext && if (algo !== enums[type].plaintext &&
algo !== enums.symmetric.idea && // not implemented algo !== enums[type].idea && // not implemented
enums.read(enums.symmetric, algo) && // known algorithm enums.read(enums[type], algo) && // known algorithm
prioMap[algo].count === keys.length && // available for all keys prioMap[algo].count === keys.length && // available for all keys
prioMap[algo].prio > prefAlgo.prio) { prioMap[algo].prio > prefAlgo.prio) {
prefAlgo = prioMap[algo]; prefAlgo = prioMap[algo];
@ -1471,43 +1474,21 @@ export async function getPreferredSymAlgo(keys, date) {
} }
/** /**
* Returns the preferred aead algorithm for a set of keys * Returns whether aead is supported by all keys in the set
* @param {Array<module:key.Key>} keys Set of keys * @param {Array<module:key.Key>} keys Set of keys
* @param {Date} date (optional) use the given date for verification instead of the current time * @param {Date} date (optional) use the given date for verification instead of the current time
* @returns {Promise<module:enums.aead>} Preferred aead algorithm, or null if the public keys do not support aead * @returns {Promise<Boolean>}
* @async * @async
*/ */
export async function getPreferredAeadAlgo(keys, date) { export async function isAeadSupported(keys, date) {
let supports_aead = true; let supported = true;
const prioMap = {}; // TODO replace when Promise.some or Promise.any are implemented
await Promise.all(keys.map(async function(key) { await Promise.all(keys.map(async function(key) {
const primaryUser = await key.getPrimaryUser(date); const primaryUser = await key.getPrimaryUser(date);
if (!primaryUser || !primaryUser.selfCertification.features || if (!primaryUser || !primaryUser.selfCertification.features ||
!(primaryUser.selfCertification.features[0] & enums.features.aead)) { !(primaryUser.selfCertification.features[0] & enums.features.aead)) {
supports_aead = false; supported = false;
return;
} }
if (!primaryUser || !primaryUser.selfCertification.preferredAeadAlgorithms) {
return config.aead_mode;
}
primaryUser.selfCertification.preferredAeadAlgorithms.forEach(function(algo, index) {
const entry = prioMap[algo] || (prioMap[algo] = { prio: 0, count: 0, algo: algo });
entry.prio += 64 >> index;
entry.count++;
});
})); }));
if (!supports_aead) { return supported;
return null;
}
let prefAlgo = { prio: 0, algo: config.aead_mode };
for (const algo in prioMap) {
try {
if (enums.read(enums.aead, algo) && // known algorithm
prioMap[algo].count === keys.length && // available for all keys
prioMap[algo].prio > prefAlgo.prio) {
prefAlgo = prioMap[algo];
}
} catch (e) {}
}
return prefAlgo.algo;
} }

View File

@ -36,7 +36,7 @@ import enums from './enums';
import util from './util'; import util from './util';
import packet from './packet'; import packet from './packet';
import { Signature } from './signature'; import { Signature } from './signature';
import { getPreferredHashAlgo, getPreferredSymAlgo, getPreferredAeadAlgo } from './key'; import { getPreferredHashAlgo, getPreferredAlgo, isAeadSupported } from './key';
/** /**
@ -263,10 +263,9 @@ Message.prototype.encrypt = async function(keys, passwords, sessionKey, wildcard
aeadAlgo = sessionKey.aeadAlgorithm; aeadAlgo = sessionKey.aeadAlgorithm;
sessionKey = sessionKey.data; sessionKey = sessionKey.data;
} else if (keys && keys.length) { } else if (keys && keys.length) {
symAlgo = enums.read(enums.symmetric, await getPreferredSymAlgo(keys, date)); symAlgo = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', keys, date));
aeadAlgo = await getPreferredAeadAlgo(keys, date); if (config.aead_protect && config.aead_protect_version === 4 && await isAeadSupported(keys, date)) {
if (aeadAlgo) { aeadAlgo = enums.read(enums.aead, await getPreferredAlgo('aead', keys, date));
aeadAlgo = enums.read(enums.aead, aeadAlgo);
} }
} else if (passwords && passwords.length) { } else if (passwords && passwords.length) {
symAlgo = enums.read(enums.symmetric, config.encryption_cipher); symAlgo = enums.read(enums.symmetric, config.encryption_cipher);

View File

@ -1170,42 +1170,44 @@ p92yZgB3r2+f6/GIe2+7
}); });
}); });
it('getPreferredSymAlgo() - one key - AES256', async function() { it("getPreferredAlgo('symmetric') - one key - AES256", async function() {
const key1 = openpgp.key.readArmored(twoKeys).keys[0]; const key1 = openpgp.key.readArmored(twoKeys).keys[0];
const prefAlgo = await openpgp.key.getPreferredSymAlgo([key1]); const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1]);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256); expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256);
}); });
it('getPreferredSymAlgo() - two key - AES128', async function() { it("getPreferredAlgo('symmetric') - two key - AES128", async function() {
const keys = openpgp.key.readArmored(twoKeys).keys; const keys = openpgp.key.readArmored(twoKeys).keys;
const key1 = keys[0]; const key1 = keys[0];
const key2 = keys[1]; const key2 = keys[1];
const primaryUser = await key2.getPrimaryUser(); const primaryUser = await key2.getPrimaryUser();
primaryUser.selfCertification.preferredSymmetricAlgorithms = [6,7,3]; primaryUser.selfCertification.preferredSymmetricAlgorithms = [6,7,3];
const prefAlgo = await openpgp.key.getPreferredSymAlgo([key1, key2]); const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1, key2]);
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128); expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128);
}); });
it('getPreferredSymAlgo() - two key - one without pref', async function() { it("getPreferredAlgo('symmetric') - two key - one without pref", async function() {
const keys = openpgp.key.readArmored(twoKeys).keys; const keys = openpgp.key.readArmored(twoKeys).keys;
const key1 = keys[0]; const key1 = keys[0];
const key2 = keys[1]; const key2 = keys[1];
const primaryUser = await key2.getPrimaryUser(); const primaryUser = await key2.getPrimaryUser();
primaryUser.selfCertification.preferredSymmetricAlgorithms = null; primaryUser.selfCertification.preferredSymmetricAlgorithms = null;
const prefAlgo = await openpgp.key.getPreferredSymAlgo([key1, key2]); const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1, key2]);
expect(prefAlgo).to.equal(openpgp.config.encryption_cipher); expect(prefAlgo).to.equal(openpgp.config.encryption_cipher);
}); });
it('getPreferredAeadAlgo() - one key - OCB', async function() { it("getPreferredAlgo('aead') - one key - OCB", async function() {
const key1 = openpgp.key.readArmored(twoKeys).keys[0]; const key1 = openpgp.key.readArmored(twoKeys).keys[0];
const primaryUser = await key1.getPrimaryUser(); const primaryUser = await key1.getPrimaryUser();
primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
primaryUser.selfCertification.preferredAeadAlgorithms = [2,1]; primaryUser.selfCertification.preferredAeadAlgorithms = [2,1];
const prefAlgo = await openpgp.key.getPreferredAeadAlgo([key1]); const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1]);
expect(prefAlgo).to.equal(openpgp.enums.aead.ocb); expect(prefAlgo).to.equal(openpgp.enums.aead.ocb);
const supported = await openpgp.key.isAeadSupported([key1]);
expect(supported).to.be.true;
}); });
it('getPreferredAeadAlgo() - two key - one without pref', async function() { it("getPreferredAlgo('aead') - two key - one without pref", async function() {
const keys = openpgp.key.readArmored(twoKeys).keys; const keys = openpgp.key.readArmored(twoKeys).keys;
const key1 = keys[0]; const key1 = keys[0];
const key2 = keys[1]; const key2 = keys[1];
@ -1214,19 +1216,23 @@ p92yZgB3r2+f6/GIe2+7
primaryUser.selfCertification.preferredAeadAlgorithms = [2,1]; primaryUser.selfCertification.preferredAeadAlgorithms = [2,1];
const primaryUser2 = await key2.getPrimaryUser(); const primaryUser2 = await key2.getPrimaryUser();
primaryUser2.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser2.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
const prefAlgo = await openpgp.key.getPreferredAeadAlgo([key1, key2]); const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]);
expect(prefAlgo).to.equal(openpgp.config.aead_mode); expect(prefAlgo).to.equal(openpgp.config.aead_mode);
const supported = await openpgp.key.isAeadSupported([key1, key2]);
expect(supported).to.be.true;
}); });
it('getPreferredAeadAlgo() - two key - one with no support', async function() { it("getPreferredAlgo('aead') - two key - one with no support", async function() {
const keys = openpgp.key.readArmored(twoKeys).keys; const keys = openpgp.key.readArmored(twoKeys).keys;
const key1 = keys[0]; const key1 = keys[0];
const key2 = keys[1]; const key2 = keys[1];
const primaryUser = await key1.getPrimaryUser(); const primaryUser = await key1.getPrimaryUser();
primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag
primaryUser.selfCertification.preferredAeadAlgorithms = [2,1]; primaryUser.selfCertification.preferredAeadAlgorithms = [2,1];
const prefAlgo = await openpgp.key.getPreferredAeadAlgo([key1, key2]); const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]);
expect(prefAlgo).to.be.null; expect(prefAlgo).to.equal(openpgp.config.aead_mode);
const supported = await openpgp.key.isAeadSupported([key1, key2]);
expect(supported).to.be.false;
}); });
it('Preferences of generated key', function() { it('Preferences of generated key', function() {