diff --git a/src/key.js b/src/key.js index 65da1173..0d58a2a3 100644 --- a/src/key.js +++ b/src/key.js @@ -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} keys Set of keys * @param {Date} date (optional) use the given date for verification instead of the current time * @returns {Promise} Preferred symmetric algorithm * @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 = {}; await Promise.all(keys.map(async function(key) { const primaryUser = await key.getPrimaryUser(date); - if (!primaryUser || !primaryUser.selfCertification.preferredSymmetricAlgorithms) { - return config.encryption_cipher; + if (!primaryUser || !primaryUser.selfCertification[prefProperty]) { + 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 }); entry.prio += 64 >> index; entry.count++; }); })); - let prefAlgo = { prio: 0, algo: config.encryption_cipher }; + let prefAlgo = { prio: 0, algo: defaultAlgo }; for (const algo in prioMap) { try { - if (algo !== enums.symmetric.plaintext && - algo !== enums.symmetric.idea && // not implemented - enums.read(enums.symmetric, algo) && // known algorithm + if (algo !== enums[type].plaintext && + algo !== enums[type].idea && // not implemented + enums.read(enums[type], algo) && // known algorithm prioMap[algo].count === keys.length && // available for all keys prioMap[algo].prio > prefAlgo.prio) { 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} keys Set of keys * @param {Date} date (optional) use the given date for verification instead of the current time - * @returns {Promise} Preferred aead algorithm, or null if the public keys do not support aead + * @returns {Promise} * @async */ -export async function getPreferredAeadAlgo(keys, date) { - let supports_aead = true; - const prioMap = {}; +export async function isAeadSupported(keys, date) { + let supported = true; + // TODO replace when Promise.some or Promise.any are implemented await Promise.all(keys.map(async function(key) { const primaryUser = await key.getPrimaryUser(date); if (!primaryUser || !primaryUser.selfCertification.features || !(primaryUser.selfCertification.features[0] & enums.features.aead)) { - supports_aead = false; - return; + supported = false; } - 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 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; + return supported; } diff --git a/src/message.js b/src/message.js index ec7944ef..7ce2cb2f 100644 --- a/src/message.js +++ b/src/message.js @@ -36,7 +36,7 @@ import enums from './enums'; import util from './util'; import packet from './packet'; 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; sessionKey = sessionKey.data; } else if (keys && keys.length) { - symAlgo = enums.read(enums.symmetric, await getPreferredSymAlgo(keys, date)); - aeadAlgo = await getPreferredAeadAlgo(keys, date); - if (aeadAlgo) { - aeadAlgo = enums.read(enums.aead, aeadAlgo); + symAlgo = enums.read(enums.symmetric, await getPreferredAlgo('symmetric', keys, date)); + if (config.aead_protect && config.aead_protect_version === 4 && await isAeadSupported(keys, date)) { + aeadAlgo = enums.read(enums.aead, await getPreferredAlgo('aead', keys, date)); } } else if (passwords && passwords.length) { symAlgo = enums.read(enums.symmetric, config.encryption_cipher); diff --git a/test/general/key.js b/test/general/key.js index ec21ac20..8354423e 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -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 prefAlgo = await openpgp.key.getPreferredSymAlgo([key1]); + const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1]); 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 key1 = keys[0]; const key2 = keys[1]; const primaryUser = await key2.getPrimaryUser(); 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); }); - 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 key1 = keys[0]; const key2 = keys[1]; const primaryUser = await key2.getPrimaryUser(); 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); }); - it('getPreferredAeadAlgo() - one key - OCB', async function() { + it("getPreferredAlgo('aead') - one key - OCB", async function() { const key1 = openpgp.key.readArmored(twoKeys).keys[0]; const primaryUser = await key1.getPrimaryUser(); primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag 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); + 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 key1 = keys[0]; const key2 = keys[1]; @@ -1214,19 +1216,23 @@ p92yZgB3r2+f6/GIe2+7 primaryUser.selfCertification.preferredAeadAlgorithms = [2,1]; const primaryUser2 = await key2.getPrimaryUser(); 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); + 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 key1 = keys[0]; const key2 = keys[1]; const primaryUser = await key1.getPrimaryUser(); primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser.selfCertification.preferredAeadAlgorithms = [2,1]; - const prefAlgo = await openpgp.key.getPreferredAeadAlgo([key1, key2]); - expect(prefAlgo).to.be.null; + const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]); + 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() {