Simplify algorithm preference selection and normalize config names (#1262)

- Rename `config.compression` to `config.preferredCompressionAlgorithm`
- Rename `config.encryptionCipher` to `config.preferredSymmetricAlgorithm`
- Rename `config.preferHashAlgorithm` to `config.preferredHashAlgorithm`
- Rename `config.aeadMode` to `config.preferredAeadAlgorithm`
- When encrypting to public keys, the compression/aead/symmetric algorithm is selected by:
  - taking the preferred algorithm specified in config, if it is supported by all recipients
  - otherwise, taking the "MUST implement" algorithm specified by rfc4880bis
- When encrypting to passphrases only (no public keys), the preferred algorithms from `config` are always used
- EdDSA signing with a hash algorithm weaker than sha256 is explicitly disallowed (https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2)
This commit is contained in:
larabr 2021-03-10 18:06:03 +01:00 committed by GitHub
parent 4379d1856e
commit 43fb58404d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 145 additions and 138 deletions

View File

@ -79,9 +79,9 @@ library to convert back and forth between them.
You can change the AEAD mode by setting one of the following options: You can change the AEAD mode by setting one of the following options:
``` ```
openpgp.config.aeadMode = openpgp.enums.aead.eax // Default, native openpgp.config.preferredAeadAlgorithm = openpgp.enums.aead.eax // Default, native
openpgp.config.aeadMode = openpgp.enums.aead.ocb // Non-native openpgp.config.preferredAeadAlgorithm = openpgp.enums.aead.ocb // Non-native
openpgp.config.aeadMode = openpgp.enums.aead.experimentalGcm // **Non-standard**, fastest openpgp.config.preferredAeadAlgorithm = openpgp.enums.aead.experimentalGcm // **Non-standard**, fastest
``` ```
* For environments that don't provide native crypto, the library falls back to [asm.js](https://caniuse.com/#feat=asmjs) implementations of AES, SHA-1, and SHA-256. * For environments that don't provide native crypto, the library falls back to [asm.js](https://caniuse.com/#feat=asmjs) implementations of AES, SHA-1, and SHA-256.
@ -169,7 +169,7 @@ Here are some examples of how to use OpenPGP.js v5. For more elaborate examples
#### Encrypt and decrypt *Uint8Array* data with a password #### Encrypt and decrypt *Uint8Array* data with a password
Encryption will use the algorithm specified in config.encryptionCipher (defaults to aes256), and decryption will use the algorithm used for encryption. Encryption will use the algorithm specified in config.preferredSymmetricAlgorithm (defaults to aes256), and decryption will use the algorithm used for encryption.
```js ```js
(async () => { (async () => {
@ -267,11 +267,10 @@ Encrypt with multiple public keys:
})(); })();
``` ```
#### Encrypt with compression #### Encrypt symmetrically with compression
By default, `encrypt` will not use any compression. It's possible to override that behavior in two ways: By default, `encrypt` will not use any compression when encrypting symmetrically only (i.e. when no `publicKeys` are given).
It's possible to change that behaviour by enabling compression through the config, either for the single encryption:
Either set the `compression` parameter in the options object when calling `encrypt`.
```js ```js
(async () => { (async () => {
@ -279,20 +278,21 @@ Either set the `compression` parameter in the options object when calling `encry
const encrypted = await openpgp.encrypt({ const encrypted = await openpgp.encrypt({
message, message,
passwords: ['secret stuff'], // multiple passwords possible passwords: ['secret stuff'], // multiple passwords possible
compression: openpgp.enums.compression.zip // compress the data with zip config: { preferredCompressionAlgorithm: openpgp.enums.compression.zlib } // compress the data with zlib
}); });
})(); })();
``` ```
Or, override the config to enable compression: or by changing the default global configuration:
```js ```js
openpgp.config.compression = openpgp.enums.compression.zlib; openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.zlib
``` ```
Where the value can be any of: Where the value can be any of:
* `openpgp.enums.compression.zip` * `openpgp.enums.compression.zip`
* `openpgp.enums.compression.zlib` * `openpgp.enums.compression.zlib`
* `openpgp.enums.compression.uncompressed` (default)
#### Streaming encrypt *Uint8Array* data with a password #### Streaming encrypt *Uint8Array* data with a password

6
openpgp.d.ts vendored
View File

@ -300,9 +300,9 @@ export class Message<T extends MaybeStream<Data>> {
/* ############## v5 CONFIG #################### */ /* ############## v5 CONFIG #################### */
interface Config { interface Config {
preferHashAlgorithm: enums.hash; preferredHashAlgorithm: enums.hash;
encryptionCipher: enums.symmetric; preferredSymmetricAlgorithm: enums.symmetric;
compression: enums.compression; preferredCompressionAlgorithm: enums.compression;
showVersion: boolean; showVersion: boolean;
showComment: boolean; showComment: boolean;
deflateLevel: number; deflateLevel: number;

View File

@ -24,19 +24,19 @@ import enums from '../enums';
export default { export default {
/** /**
* @memberof module:config * @memberof module:config
* @property {Integer} preferHashAlgorithm Default hash algorithm {@link module:enums.hash} * @property {Integer} preferredHashAlgorithm Default hash algorithm {@link module:enums.hash}
*/ */
preferHashAlgorithm: enums.hash.sha256, preferredHashAlgorithm: enums.hash.sha256,
/** /**
* @memberof module:config * @memberof module:config
* @property {Integer} encryptionCipher Default encryption cipher {@link module:enums.symmetric} * @property {Integer} preferredSymmetricAlgorithm Default encryption cipher {@link module:enums.symmetric}
*/ */
encryptionCipher: enums.symmetric.aes256, preferredSymmetricAlgorithm: enums.symmetric.aes256,
/** /**
* @memberof module:config * @memberof module:config
* @property {Integer} compression Default compression algorithm {@link module:enums.compression} * @property {Integer} compression Default compression algorithm {@link module:enums.compression}
*/ */
compression: enums.compression.uncompressed, preferredCompressionAlgorithm: enums.compression.uncompressed,
/** /**
* @memberof module:config * @memberof module:config
* @property {Integer} deflateLevel Default zip/zlib compression level, between 1 and 9 * @property {Integer} deflateLevel Default zip/zlib compression level, between 1 and 9
@ -56,9 +56,9 @@ export default {
* Default Authenticated Encryption with Additional Data (AEAD) encryption mode * Default Authenticated Encryption with Additional Data (AEAD) encryption mode
* Only has an effect when aeadProtect is set to true. * Only has an effect when aeadProtect is set to true.
* @memberof module:config * @memberof module:config
* @property {Integer} aeadMode Default AEAD mode {@link module:enums.aead} * @property {Integer} preferredAeadAlgorithm Default AEAD mode {@link module:enums.aead}
*/ */
aeadMode: enums.aead.eax, preferredAeadAlgorithm: enums.aead.eax,
/** /**
* Chunk Size Byte for Authenticated Encryption with Additional Data (AEAD) mode * Chunk Size Byte for Authenticated Encryption with Additional Data (AEAD) mode
* Only has an effect when aeadProtect is set to true. * Only has an effect when aeadProtect is set to true.

View File

@ -24,13 +24,15 @@
import sha512 from 'hash.js/lib/hash/sha/512'; import sha512 from 'hash.js/lib/hash/sha/512';
import nacl from '@openpgp/tweetnacl/nacl-fast-light.js'; import nacl from '@openpgp/tweetnacl/nacl-fast-light.js';
import util from '../../../util'; import util from '../../../util';
import enums from '../../../enums';
import hash from '../../hash';
nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest()); nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest());
/** /**
* Sign a message using the provided key * Sign a message using the provided key
* @param {module:type/oid} oid - Elliptic curve object identifier * @param {module:type/oid} oid - Elliptic curve object identifier
* @param {module:enums.hash} hash_algo - Hash algorithm used to sign * @param {module:enums.hash} hash_algo - Hash algorithm used to sign (must be sha256 or stronger)
* @param {Uint8Array} message - Message to sign * @param {Uint8Array} message - Message to sign
* @param {Uint8Array} publicKey - Public key * @param {Uint8Array} publicKey - Public key
* @param {Uint8Array} privateKey - Private key used to sign the message * @param {Uint8Array} privateKey - Private key used to sign the message
@ -40,6 +42,10 @@ nacl.hash = bytes => new Uint8Array(sha512().update(bytes).digest());
* @async * @async
*/ */
export async function sign(oid, hash_algo, message, publicKey, privateKey, hashed) { export async function sign(oid, hash_algo, message, publicKey, privateKey, hashed) {
if (hash.getHashByteLength(hash_algo) < hash.getHashByteLength(enums.hash.sha256)) {
// see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
throw new Error('Hash algorithm too weak: sha256 or stronger is required for EdDSA.');
}
const secretKey = util.concatUint8Array([privateKey, publicKey.subarray(1)]); const secretKey = util.concatUint8Array([privateKey, publicKey.subarray(1)]);
const signature = nacl.sign.detached(hashed, secretKey); const signature = nacl.sign.detached(hashed, secretKey);
// EdDSA signature params are returned in little-endian format // EdDSA signature params are returned in little-endian format

View File

@ -134,17 +134,8 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
packetlist.push(secretKeyPacket); packetlist.push(secretKeyPacket);
await Promise.all(options.userIds.map(async function(userId, index) { await Promise.all(options.userIds.map(async function(userId, index) {
function createdPreferredAlgos(algos, configAlgo) { function createPreferredAlgos(algos, preferredAlgo) {
if (configAlgo) { // Not `uncompressed` / `plaintext` return [preferredAlgo, ...algos.filter(algo => algo !== preferredAlgo)];
const configIndex = algos.indexOf(configAlgo);
if (configIndex >= 1) { // If it is included and not in first place,
algos.splice(configIndex, 1); // remove it.
}
if (configIndex !== 0) { // If it was included and not in first place, or wasn't included,
algos.unshift(configAlgo); // add it to the front.
}
}
return algos;
} }
const userIdPacket = UserIDPacket.fromObject(userId); const userIdPacket = UserIDPacket.fromObject(userId);
@ -156,28 +147,28 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm; signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm;
signaturePacket.hashAlgorithm = await helper.getPreferredHashAlgo(null, secretKeyPacket, undefined, undefined, config); signaturePacket.hashAlgorithm = await helper.getPreferredHashAlgo(null, secretKeyPacket, undefined, undefined, config);
signaturePacket.keyFlags = [enums.keyFlags.certifyKeys | enums.keyFlags.signData]; signaturePacket.keyFlags = [enums.keyFlags.certifyKeys | enums.keyFlags.signData];
signaturePacket.preferredSymmetricAlgorithms = createdPreferredAlgos([ signaturePacket.preferredSymmetricAlgorithms = createPreferredAlgos([
// prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support) // prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
enums.symmetric.aes256, enums.symmetric.aes256,
enums.symmetric.aes128, enums.symmetric.aes128,
enums.symmetric.aes192 enums.symmetric.aes192
], config.encryptionCipher); ], config.preferredSymmetricAlgorithm);
if (config.aeadProtect) { if (config.aeadProtect) {
signaturePacket.preferredAeadAlgorithms = createdPreferredAlgos([ signaturePacket.preferredAeadAlgorithms = createPreferredAlgos([
enums.aead.eax, enums.aead.eax,
enums.aead.ocb enums.aead.ocb
], config.aeadMode); ], config.preferredAeadAlgorithm);
} }
signaturePacket.preferredHashAlgorithms = createdPreferredAlgos([ signaturePacket.preferredHashAlgorithms = createPreferredAlgos([
// prefer fast asm.js implementations (SHA-256) // prefer fast asm.js implementations (SHA-256)
enums.hash.sha256, enums.hash.sha256,
enums.hash.sha512 enums.hash.sha512
], config.preferHashAlgorithm); ], config.preferredHashAlgorithm);
signaturePacket.preferredCompressionAlgorithms = createdPreferredAlgos([ signaturePacket.preferredCompressionAlgorithms = createPreferredAlgos([
enums.compression.zlib, enums.compression.zlib,
enums.compression.zip, enums.compression.zip,
enums.compression.uncompressed enums.compression.uncompressed
], config.compression); ], config.preferredCompressionAlgorithm);
if (index === 0) { if (index === 0) {
signaturePacket.isPrimaryUserID = true; signaturePacket.isPrimaryUserID = true;
} }

View File

@ -132,7 +132,7 @@ export async function createBindingSignature(subkey, primaryKey, options, config
* @async * @async
*/ */
export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), userId = {}, config) { export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), userId = {}, config) {
let hash_algo = config.preferHashAlgorithm; let hash_algo = config.preferredHashAlgorithm;
let pref_algo = hash_algo; let pref_algo = hash_algo;
if (key) { if (key) {
const primaryUser = await key.getPrimaryUser(date, userId, config); const primaryUser = await key.getPrimaryUser(date, userId, config);
@ -159,43 +159,41 @@ export async function getPreferredHashAlgo(key, keyPacket, date = new Date(), us
} }
/** /**
* Returns the preferred symmetric/aead algorithm for a set of keys * Returns the preferred symmetric/aead/compression algorithm for a set of keys
* @param {symmetric|aead} type - Type of preference to return * @param {symmetric|aead|compression} type - Type of preference to return
* @param {Array<Key>} keys - Set of keys * @param {Array<Key>} [keys] - Set of keys
* @param {Date} [date] - Use the given date for verification instead of the current time * @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Array} [userIds] - User IDs * @param {Array} [userIds] - User IDs
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {module:enums.symmetric} Preferred symmetric algorithm. * @returns {module:enums.symmetric|aead|compression} Preferred algorithm
* @async * @async
*/ */
export async function getPreferredAlgo(type, keys, date = new Date(), userIds = [], config = defaultConfig) { export async function getPreferredAlgo(type, keys = [], date = new Date(), userIds = [], config = defaultConfig) {
const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms'; const defaultAlgo = { // these are all must-implement in rfc4880bis
const defaultAlgo = type === 'symmetric' ? enums.symmetric.aes128 : enums.aead.eax; 'symmetric': enums.symmetric.aes128,
const prioMap = {}; 'aead': enums.aead.eax,
await Promise.all(keys.map(async function(key, i) { 'compression': enums.compression.uncompressed
}[type];
const preferredSenderAlgo = {
'symmetric': config.preferredSymmetricAlgorithm,
'aead': config.preferredAeadAlgorithm,
'compression': config.preferredCompressionAlgorithm
}[type];
const prefPropertyName = {
'symmetric': 'preferredSymmetricAlgorithms',
'aead': 'preferredAeadAlgorithms',
'compression': 'preferredCompressionAlgorithms'
}[type];
// if preferredSenderAlgo appears in the prefs of all recipients, we pick it
// otherwise we use the default algo
// if no keys are available, preferredSenderAlgo is returned
const senderAlgoSupport = await Promise.all(keys.map(async function(key, i) {
const primaryUser = await key.getPrimaryUser(date, userIds[i], config); const primaryUser = await key.getPrimaryUser(date, userIds[i], config);
if (!primaryUser.selfCertification[prefProperty]) { const recipientPrefs = primaryUser.selfCertification[prefPropertyName];
return defaultAlgo; return !!recipientPrefs && recipientPrefs.indexOf(preferredSenderAlgo) >= 0;
}
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: defaultAlgo }; return senderAlgoSupport.every(Boolean) ? preferredSenderAlgo : defaultAlgo;
Object.values(prioMap).forEach(({ prio, count, algo }) => {
try {
if (algo !== enums[type].plaintext &&
algo !== enums[type].idea && // not implemented
enums.read(enums[type], algo) && // known algorithm
count === keys.length && // available for all keys
prio > prefAlgo.prio) {
prefAlgo = prioMap[algo];
}
} catch (e) {}
});
return prefAlgo.algo;
} }
/** /**

View File

@ -37,7 +37,6 @@ import {
import { Signature } from './signature'; import { Signature } from './signature';
import { getPreferredHashAlgo, getPreferredAlgo, isAeadSupported, createSignaturePacket } from './key'; import { getPreferredHashAlgo, getPreferredAlgo, isAeadSupported, createSignaturePacket } from './key';
/** /**
* Class that represents an OpenPGP message. * Class that represents an OpenPGP message.
* Can be an encrypted message, signed message, compressed message or literal message * Can be an encrypted message, signed message, compressed message or literal message
@ -287,6 +286,7 @@ export class Message {
const aeadAlgorithm = config.aeadProtect && await isAeadSupported(keys, date, userIds, config) ? const aeadAlgorithm = config.aeadProtect && await isAeadSupported(keys, date, userIds, config) ?
enums.read(enums.aead, await getPreferredAlgo('aead', keys, date, userIds, config)) : enums.read(enums.aead, await getPreferredAlgo('aead', keys, date, userIds, config)) :
undefined; undefined;
const sessionKeyData = await crypto.generateSessionKey(algorithm); const sessionKeyData = await crypto.generateSessionKey(algorithm);
return { data: sessionKeyData, algorithm, aeadAlgorithm }; return { data: sessionKeyData, algorithm, aeadAlgorithm };
} }
@ -478,15 +478,17 @@ export class Message {
/** /**
* Compresses the message (the literal and -if signed- signature data packets of the message) * Compresses the message (the literal and -if signed- signature data packets of the message)
* @param {module:enums.compression} algo - compression algorithm
* @param {Object} [config] - Full configuration, defaults to openpgp.config * @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Message} New message with compressed content. * @returns {Message} New message with compressed content.
*/ */
compress(config = defaultConfig) { compress(algo, config = defaultConfig) {
if (config.compression === enums.compression.uncompressed) { if (algo === enums.compression.uncompressed) {
return this; return this;
} }
const compressed = new CompressedDataPacket(config); const compressed = new CompressedDataPacket(config);
compressed.algorithm = enums.read(enums.compression, algo);
compressed.packets = this.packets; compressed.packets = this.packets;
const packetList = new PacketList(); const packetList = new PacketList();

View File

@ -19,7 +19,7 @@ import stream from '@openpgp/web-stream-tools';
import { createReadableStreamWrapper } from '@mattiasbuelens/web-streams-adapter'; import { createReadableStreamWrapper } from '@mattiasbuelens/web-streams-adapter';
import { Message } from './message'; import { Message } from './message';
import { CleartextMessage } from './cleartext'; import { CleartextMessage } from './cleartext';
import { generate, reformat } from './key'; import { generate, reformat, getPreferredAlgo } from './key';
import defaultConfig from './config'; import defaultConfig from './config';
import util from './util'; import util from './util';
@ -264,7 +264,10 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe
if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified
message = await message.sign(privateKeys, signature, signingKeyIds, date, fromUserIds, message.fromStream, config); message = await message.sign(privateKeys, signature, signingKeyIds, date, fromUserIds, message.fromStream, config);
} }
message = message.compress(config); message = message.compress(
await getPreferredAlgo('compression', publicKeys, date, toUserIds, config),
config
);
message = await message.encrypt(publicKeys, passwords, sessionKey, wildcard, encryptionKeyIds, date, toUserIds, streaming, config); message = await message.encrypt(publicKeys, passwords, sessionKey, wildcard, encryptionKeyIds, date, toUserIds, streaming, config);
const data = armor ? message.armor(config) : message.write(); const data = armor ? message.armor(config) : message.write();
return convertStream(data, streaming, armor ? 'utf8' : 'binary'); return convertStream(data, streaming, armor ? 'utf8' : 'binary');

View File

@ -56,7 +56,7 @@ class CompressedDataPacket {
* Compression algorithm * Compression algorithm
* @type {compression} * @type {compression}
*/ */
this.algorithm = enums.read(enums.compression, config.compression); this.algorithm = enums.read(enums.compression, config.preferredCompressionAlgorithm);
/** /**
* Compressed packet data * Compressed packet data

View File

@ -44,7 +44,7 @@ class SymEncryptedSessionKeyPacket {
this.sessionKey = null; this.sessionKey = null;
this.sessionKeyEncryptionAlgorithm = null; this.sessionKeyEncryptionAlgorithm = null;
this.sessionKeyAlgorithm = 'aes256'; this.sessionKeyAlgorithm = 'aes256';
this.aeadAlgorithm = enums.read(enums.aead, config.aeadMode); this.aeadAlgorithm = enums.read(enums.aead, config.preferredAeadAlgorithm);
this.encrypted = null; this.encrypted = null;
this.s2k = null; this.s2k = null;
this.iv = null; this.iv = null;

View File

@ -5,10 +5,10 @@ const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp
module.exports = () => describe('Custom configuration', function() { module.exports = () => describe('Custom configuration', function() {
it('openpgp.generateKey', async function() { it('openpgp.generateKey', async function() {
const v5KeysVal = openpgp.config.v5Keys; const v5KeysVal = openpgp.config.v5Keys;
const preferHashAlgorithmVal = openpgp.config.preferHashAlgorithm; const preferredHashAlgorithmVal = openpgp.config.preferredHashAlgorithm;
const showCommentVal = openpgp.config.showComment; const showCommentVal = openpgp.config.showComment;
openpgp.config.v5Keys = false; openpgp.config.v5Keys = false;
openpgp.config.preferHashAlgorithm = openpgp.enums.hash.sha256; openpgp.config.preferredHashAlgorithm = openpgp.enums.hash.sha256;
openpgp.config.showComment = false; openpgp.config.showComment = false;
try { try {
@ -18,12 +18,12 @@ module.exports = () => describe('Custom configuration', function() {
const { key, privateKeyArmored } = await openpgp.generateKey(opt); const { key, privateKeyArmored } = await openpgp.generateKey(opt);
expect(key.keyPacket.version).to.equal(4); expect(key.keyPacket.version).to.equal(4);
expect(privateKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false; expect(privateKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(openpgp.config.preferHashAlgorithm); expect(key.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm);
const config = { const config = {
v5Keys: true, v5Keys: true,
showComment: true, showComment: true,
preferHashAlgorithm: openpgp.enums.hash.sha512 preferredHashAlgorithm: openpgp.enums.hash.sha512
}; };
const opt2 = { const opt2 = {
userIds: { name: 'Test User', email: 'text@example.com' }, userIds: { name: 'Test User', email: 'text@example.com' },
@ -32,20 +32,20 @@ module.exports = () => describe('Custom configuration', function() {
const { key: key2, privateKeyArmored: privateKeyArmored2 } = await openpgp.generateKey(opt2); const { key: key2, privateKeyArmored: privateKeyArmored2 } = await openpgp.generateKey(opt2);
expect(key2.keyPacket.version).to.equal(5); expect(key2.keyPacket.version).to.equal(5);
expect(privateKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true; expect(privateKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
expect(key2.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(config.preferHashAlgorithm); expect(key2.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm);
} finally { } finally {
openpgp.config.v5Keys = v5KeysVal; openpgp.config.v5Keys = v5KeysVal;
openpgp.config.preferHashAlgorithm = preferHashAlgorithmVal; openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal;
openpgp.config.showComment = showCommentVal; openpgp.config.showComment = showCommentVal;
} }
}); });
it('openpgp.reformatKey', async function() { it('openpgp.reformatKey', async function() {
const compressionVal = openpgp.config.compression; const preferredCompressionAlgorithmVal = openpgp.config.preferredCompressionAlgorithm;
const preferHashAlgorithmVal = openpgp.config.preferHashAlgorithm; const preferredHashAlgorithmVal = openpgp.config.preferredHashAlgorithm;
const showCommentVal = openpgp.config.showComment; const showCommentVal = openpgp.config.showComment;
openpgp.config.compression = openpgp.enums.compression.bzip2; openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.bzip2;
openpgp.config.preferHashAlgorithm = openpgp.enums.hash.sha256; openpgp.config.preferredHashAlgorithm = openpgp.enums.hash.sha256;
openpgp.config.showComment = false; openpgp.config.showComment = false;
try { try {
@ -55,24 +55,24 @@ module.exports = () => describe('Custom configuration', function() {
const opt = { privateKey: origKey, userIds }; const opt = { privateKey: origKey, userIds };
const { key: refKey, privateKeyArmored: refKeyArmored } = await openpgp.reformatKey(opt); const { key: refKey, privateKeyArmored: refKeyArmored } = await openpgp.reformatKey(opt);
const prefs = refKey.users[0].selfCertifications[0]; const prefs = refKey.users[0].selfCertifications[0];
expect(prefs.preferredCompressionAlgorithms[0]).to.equal(openpgp.config.compression); expect(prefs.preferredCompressionAlgorithms[0]).to.equal(openpgp.config.preferredCompressionAlgorithm);
expect(prefs.preferredHashAlgorithms[0]).to.equal(openpgp.config.preferHashAlgorithm); expect(prefs.preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm);
expect(refKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false; expect(refKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false;
const config = { const config = {
showComment: true, showComment: true,
compression: openpgp.enums.compression.zip, preferredCompressionAlgorithm: openpgp.enums.compression.zip,
preferHashAlgorithm: openpgp.enums.hash.sha512 preferredHashAlgorithm: openpgp.enums.hash.sha512
}; };
const opt2 = { privateKey: origKey, userIds, config }; const opt2 = { privateKey: origKey, userIds, config };
const { key: refKey2, privateKeyArmored: refKeyArmored2 } = await openpgp.reformatKey(opt2); const { key: refKey2, privateKeyArmored: refKeyArmored2 } = await openpgp.reformatKey(opt2);
const prefs2 = refKey2.users[0].selfCertifications[0]; const prefs2 = refKey2.users[0].selfCertifications[0];
expect(prefs2.preferredCompressionAlgorithms[0]).to.equal(config.compression); expect(prefs2.preferredCompressionAlgorithms[0]).to.equal(config.preferredCompressionAlgorithm);
expect(prefs2.preferredHashAlgorithms[0]).to.equal(config.preferHashAlgorithm); expect(prefs2.preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm);
expect(refKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true; expect(refKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true;
} finally { } finally {
openpgp.config.compression = compressionVal; openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal;
openpgp.config.preferHashAlgorithm = preferHashAlgorithmVal; openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal;
openpgp.config.showComment = showCommentVal; openpgp.config.showComment = showCommentVal;
} }
}); });
@ -142,9 +142,9 @@ module.exports = () => describe('Custom configuration', function() {
it('openpgp.encrypt', async function() { it('openpgp.encrypt', async function() {
const aeadProtectVal = openpgp.config.aeadProtect; const aeadProtectVal = openpgp.config.aeadProtect;
const compressionVal = openpgp.config.compression; const preferredCompressionAlgorithmVal = openpgp.config.preferredCompressionAlgorithm;
openpgp.config.aeadProtect = false; openpgp.config.aeadProtect = false;
openpgp.config.compression = openpgp.enums.compression.uncompressed; openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.uncompressed;
try { try {
const passwords = ['12345678']; const passwords = ['12345678'];
@ -160,7 +160,7 @@ module.exports = () => describe('Custom configuration', function() {
const config = { const config = {
aeadProtect: true, aeadProtect: true,
compression: openpgp.enums.compression.zip, preferredCompressionAlgorithm: openpgp.enums.compression.zip,
deflateLevel: 1 deflateLevel: 1
}; };
const armored2 = await openpgp.encrypt({ message, passwords, config }); const armored2 = await openpgp.encrypt({ message, passwords, config });
@ -173,7 +173,7 @@ module.exports = () => describe('Custom configuration', function() {
expect(compressed.algorithm).to.equal("zip"); expect(compressed.algorithm).to.equal("zip");
} finally { } finally {
openpgp.config.aeadProtect = aeadProtectVal; openpgp.config.aeadProtect = aeadProtectVal;
openpgp.config.compression = compressionVal; openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal;
} }
}); });

View File

@ -2092,7 +2092,7 @@ function versionSpecificTests() {
const hash = openpgp.enums.hash; const hash = openpgp.enums.hash;
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha256, hash.sha512]); expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha256, hash.sha512]);
const compr = openpgp.enums.compression; const compr = openpgp.enums.compression;
expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zlib, compr.zip, compr.uncompressed]); expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.uncompressed, compr.zlib, compr.zip]);
let expectedFeatures; let expectedFeatures;
if (openpgp.config.v5Keys) { if (openpgp.config.v5Keys) {
@ -2112,14 +2112,14 @@ function versionSpecificTests() {
}); });
it('Preferences of generated key - with config values', async function() { it('Preferences of generated key - with config values', async function() {
const encryptionCipherVal = openpgp.config.encryptionCipher; const preferredSymmetricAlgorithmVal = openpgp.config.preferredSymmetricAlgorithm;
const preferHashAlgorithmVal = openpgp.config.preferHashAlgorithm; const preferredHashAlgorithmVal = openpgp.config.preferredHashAlgorithm;
const compressionVal = openpgp.config.compression; const preferredCompressionAlgorithmVal = openpgp.config.preferredCompressionAlgorithm;
const aeadModeVal = openpgp.config.aeadMode; const preferredAeadAlgorithmVal = openpgp.config.preferredAeadAlgorithm;
openpgp.config.encryptionCipher = openpgp.enums.symmetric.aes192; openpgp.config.preferredSymmetricAlgorithm = openpgp.enums.symmetric.aes192;
openpgp.config.preferHashAlgorithm = openpgp.enums.hash.sha224; openpgp.config.preferredHashAlgorithm = openpgp.enums.hash.sha224;
openpgp.config.compression = openpgp.enums.compression.zlib; openpgp.config.preferredCompressionAlgorithm = openpgp.enums.compression.zip;
openpgp.config.aeadMode = openpgp.enums.aead.experimentalGcm; openpgp.config.preferredAeadAlgorithm = openpgp.enums.aead.experimentalGcm;
const testPref = function(key) { const testPref = function(key) {
// key flags // key flags
@ -2137,7 +2137,7 @@ function versionSpecificTests() {
const hash = openpgp.enums.hash; const hash = openpgp.enums.hash;
expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha224, hash.sha256, hash.sha512]); expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha224, hash.sha256, hash.sha512]);
const compr = openpgp.enums.compression; const compr = openpgp.enums.compression;
expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zlib, compr.zip, compr.uncompressed]); expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zip, compr.zlib, compr.uncompressed]);
let expectedFeatures; let expectedFeatures;
if (openpgp.config.v5Keys) { if (openpgp.config.v5Keys) {
@ -2155,10 +2155,10 @@ function versionSpecificTests() {
testPref(key.key); testPref(key.key);
testPref(await openpgp.readKey({ armoredKey: key.publicKeyArmored })); testPref(await openpgp.readKey({ armoredKey: key.publicKeyArmored }));
} finally { } finally {
openpgp.config.encryptionCipher = encryptionCipherVal; openpgp.config.preferredSymmetricAlgorithm = preferredSymmetricAlgorithmVal;
openpgp.config.preferHashAlgorithm = preferHashAlgorithmVal; openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal;
openpgp.config.compression = compressionVal; openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal;
openpgp.config.aeadMode = aeadModeVal; openpgp.config.preferredAeadAlgorithm = preferredAeadAlgorithmVal;
} }
}); });
@ -3243,26 +3243,31 @@ module.exports = () => describe('Key', function() {
expect(revKey.armor()).not.to.match(/Comment: This is a revocation certificate/); expect(revKey.armor()).not.to.match(/Comment: This is a revocation certificate/);
}); });
it("getPreferredAlgo('symmetric') - one key - AES256", async function() { it("getPreferredAlgo('symmetric') - one key", async function() {
const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys }); const [key1] = await openpgp.readKeys({ armoredKeys: twoKeys });
const prefAlgo = await key.getPreferredAlgo('symmetric', [key1]); const prefAlgo = await key.getPreferredAlgo('symmetric', [key1], undefined, undefined, {
...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256
});
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256); expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256);
}); });
it("getPreferredAlgo('symmetric') - two key - AES192", async function() { it("getPreferredAlgo('symmetric') - two key", async function() {
const keys = await openpgp.readKeys({ armoredKeys: twoKeys }); const { aes128, aes192, cast5 } = openpgp.enums.symmetric;
const key1 = keys[0]; const [key1, key2] = await openpgp.readKeys({ armoredKeys: twoKeys });
const key2 = keys[1];
const primaryUser = await key2.getPrimaryUser(); const primaryUser = await key2.getPrimaryUser();
primaryUser.selfCertification.preferredSymmetricAlgorithms = [6,8,3]; primaryUser.selfCertification.preferredSymmetricAlgorithms = [6, aes192, cast5];
const prefAlgo = await key.getPreferredAlgo('symmetric', [key1, key2]); const prefAlgo = await key.getPreferredAlgo('symmetric', [key1, key2], undefined, undefined, {
expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes192); ...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes192
});
expect(prefAlgo).to.equal(aes192);
const prefAlgo2 = await key.getPreferredAlgo('symmetric', [key1, key2], undefined, undefined, {
...openpgp.config, preferredSymmetricAlgorithm: openpgp.enums.symmetric.aes256
});
expect(prefAlgo2).to.equal(aes128);
}); });
it("getPreferredAlgo('symmetric') - two key - one without pref", async function() { it("getPreferredAlgo('symmetric') - two key - one without pref", async function() {
const keys = await openpgp.readKeys({ armoredKeys: twoKeys }); const [key1, key2] = await openpgp.readKeys({ armoredKeys: twoKeys });
const key1 = keys[0];
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 key.getPreferredAlgo('symmetric', [key1, key2]); const prefAlgo = await key.getPreferredAlgo('symmetric', [key1, key2]);
@ -3274,7 +3279,9 @@ module.exports = () => describe('Key', function() {
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 key.getPreferredAlgo('aead', [key1]); const prefAlgo = await key.getPreferredAlgo('aead', [key1], undefined, undefined, {
...openpgp.config, preferredAeadAlgorithm: openpgp.enums.aead.ocb
});
expect(prefAlgo).to.equal(openpgp.enums.aead.ocb); expect(prefAlgo).to.equal(openpgp.enums.aead.ocb);
const supported = await key.isAeadSupported([key1]); const supported = await key.isAeadSupported([key1]);
expect(supported).to.be.true; expect(supported).to.be.true;

View File

@ -685,7 +685,7 @@ function withCompression(tests) {
tests( tests(
function(options) { function(options) {
options.config = { compression }; options.config = { preferredCompressionAlgorithm: compression };
return options; return options;
}, },
function() { function() {
@ -822,7 +822,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
let publicKey; let publicKey;
let publicKeyNoAEAD; let publicKeyNoAEAD;
let aeadProtectVal; let aeadProtectVal;
let aeadModeVal; let preferredAeadAlgorithmVal;
let aeadChunkSizeByteVal; let aeadChunkSizeByteVal;
let v5KeysVal; let v5KeysVal;
let privateKeyMismatchingParams; let privateKeyMismatchingParams;
@ -840,14 +840,14 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
privateKeyMismatchingParams = await openpgp.readKey({ armoredKey: mismatchingKeyParams }); privateKeyMismatchingParams = await openpgp.readKey({ armoredKey: mismatchingKeyParams });
aeadProtectVal = openpgp.config.aeadProtect; aeadProtectVal = openpgp.config.aeadProtect;
aeadModeVal = openpgp.config.aeadMode; preferredAeadAlgorithmVal = openpgp.config.preferredAeadAlgorithm;
aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte; aeadChunkSizeByteVal = openpgp.config.aeadChunkSizeByte;
v5KeysVal = openpgp.config.v5Keys; v5KeysVal = openpgp.config.v5Keys;
}); });
afterEach(function() { afterEach(function() {
openpgp.config.aeadProtect = aeadProtectVal; openpgp.config.aeadProtect = aeadProtectVal;
openpgp.config.aeadMode = aeadModeVal; openpgp.config.preferredAeadAlgorithm = preferredAeadAlgorithmVal;
openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal; openpgp.config.aeadChunkSizeByte = aeadChunkSizeByteVal;
openpgp.config.v5Keys = v5KeysVal; openpgp.config.v5Keys = v5KeysVal;
}); });
@ -1035,7 +1035,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
if: true, if: true,
beforeEach: function() { beforeEach: function() {
openpgp.config.aeadProtect = true; openpgp.config.aeadProtect = true;
openpgp.config.aeadMode = openpgp.enums.aead.experimentalGcm; openpgp.config.preferredAeadAlgorithm = openpgp.enums.aead.experimentalGcm;
openpgp.config.v5Keys = true; openpgp.config.v5Keys = true;
// Monkey-patch AEAD feature flag // Monkey-patch AEAD feature flag
@ -1062,7 +1062,7 @@ module.exports = () => describe('OpenPGP.js public api tests', function() {
if: !openpgp.config.ci, if: !openpgp.config.ci,
beforeEach: function() { beforeEach: function() {
openpgp.config.aeadProtect = true; openpgp.config.aeadProtect = true;
openpgp.config.aeadMode = openpgp.enums.aead.ocb; openpgp.config.preferredAeadAlgorithm = openpgp.enums.aead.ocb;
// Monkey-patch AEAD feature flag // Monkey-patch AEAD feature flag
publicKey.users[0].selfCertifications[0].features = [7]; publicKey.users[0].selfCertifications[0].features = [7];

View File

@ -412,7 +412,7 @@ function tests() {
const message = await openpgp.readMessage({ const message = await openpgp.readMessage({
armoredMessage: openpgp.stream.transform(encrypted, value => { armoredMessage: openpgp.stream.transform(encrypted, value => {
value += ''; value += '';
if (value === '=' || value.length === 6) return; // Remove checksum if (value === '=' || value.length === 5) return; // Remove checksum
const newlineIndex = value.indexOf('\n', 500); const newlineIndex = value.indexOf('\n', 500);
if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex); if (value.length > 1000) return value.slice(0, newlineIndex - 1) + (value[newlineIndex - 1] === 'a' ? 'b' : 'a') + value.slice(newlineIndex);
return value; return value;

View File

@ -231,11 +231,11 @@ module.exports = () => (openpgp.config.ci ? describe.skip : describe)('X25519 Cr
const R = util.hexToUint8Array(vector.SIGNATURE.R); const R = util.hexToUint8Array(vector.SIGNATURE.R);
const S = util.hexToUint8Array(vector.SIGNATURE.S); const S = util.hexToUint8Array(vector.SIGNATURE.S);
return Promise.all([ return Promise.all([
signature.sign(22, undefined, publicParams, privateParams, undefined, data).then(({ r, s }) => { signature.sign(22, openpgp.enums.hash.sha256, publicParams, privateParams, undefined, data).then(({ r, s }) => {
expect(R).to.deep.eq(r); expect(R).to.deep.eq(r);
expect(S).to.deep.eq(s); expect(S).to.deep.eq(s);
}), }),
signature.verify(22, undefined, { r: R, s: S }, publicParams, undefined, data).then(result => { signature.verify(22, openpgp.enums.hash.sha256, { r: R, s: S }, publicParams, undefined, data).then(result => {
expect(result).to.be.true; expect(result).to.be.true;
}) })
]); ]);