mirror of
https://github.com/openpgpjs/openpgpjs.git
synced 2025-06-11 16:46:41 +00:00
Disregard config.aeadProtect
when encrypting to public keys (#1678)
Determine whether AEAD should be used for encryption solely based the encryption key preferences. Previously, the config flag was also used to control the behaviour, since AEAD messages were not standardised nor widely supported. To generate keys that declare AEAD in their preferences, use `generateKey` with `config.aeadProtect = true`.
This commit is contained in:
parent
97ebd14829
commit
105b3cdde4
@ -42,12 +42,15 @@ export default {
|
||||
* @property {Integer} deflateLevel Default zip/zlib compression level, between 1 and 9
|
||||
*/
|
||||
deflateLevel: 6,
|
||||
|
||||
/**
|
||||
* Use Authenticated Encryption with Additional Data (AEAD) protection for symmetric encryption.
|
||||
* This option is applicable to:
|
||||
* - key generation (encryption key preferences),
|
||||
* - password-based message encryption, and
|
||||
* - private key encryption.
|
||||
* In the case of message encryption using public keys, the encryption key preferences are respected instead.
|
||||
* Note: not all OpenPGP implementations are compatible with this option.
|
||||
* **FUTURE OPENPGP.JS VERSIONS MAY BREAK COMPATIBILITY WHEN USING THIS OPTION**
|
||||
* @see {@link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-07|RFC4880bis-07}
|
||||
* @see {@link https://tools.ietf.org/html/draft-ietf-openpgp-crypto-refresh-10.html|draft-crypto-refresh-10}
|
||||
* @memberof module:config
|
||||
* @property {Boolean} aeadProtect
|
||||
*/
|
||||
|
@ -168,7 +168,11 @@ export async function getPreferredCompressionAlgo(keys = [], date = new Date(),
|
||||
*/
|
||||
export async function getPreferredCipherSuite(keys = [], date = new Date(), userIDs = [], config = defaultConfig) {
|
||||
const selfSigs = await Promise.all(keys.map((key, i) => key.getPrimarySelfSignature(date, userIDs[i], config)));
|
||||
if (config.aeadProtect && selfSigs.every(selfSig => selfSig.features[0] & enums.features.seipdv2)) {
|
||||
const withAEAD = keys.length ?
|
||||
selfSigs.every(selfSig => selfSig.features[0] & enums.features.seipdv2) :
|
||||
config.aeadProtect;
|
||||
|
||||
if (withAEAD) {
|
||||
const defaultCipherSuite = { symmetricAlgo: enums.symmetric.aes128, aeadAlgo: enums.aead.ocb };
|
||||
const desiredCipherSuite = { symmetricAlgo: config.preferredSymmetricAlgorithm, aeadAlgo: config.preferredAEADAlgorithm };
|
||||
return selfSigs.every(selfSig => selfSig.preferredCipherSuites && selfSig.preferredCipherSuites.some(
|
||||
|
@ -2040,13 +2040,6 @@ aOU=
|
||||
});
|
||||
|
||||
describe('encrypt - unit tests', function() {
|
||||
it('Does not encrypt to expired key (expiration time subpacket on a direct-key signature)', async function() {
|
||||
const expiredKey = await openpgp.readKey({ armoredKey: expiredPublicKeyThroughDirectSignature });
|
||||
await expect(
|
||||
openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: expiredKey })
|
||||
).to.be.rejectedWith(/Primary key is expired/);
|
||||
});
|
||||
|
||||
it('should output message of expected format', async function() {
|
||||
const passwords = 'password';
|
||||
const text = 'test';
|
||||
@ -2213,6 +2206,55 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
|
||||
});
|
||||
expect(decrypted.data).to.equal('test');
|
||||
});
|
||||
|
||||
it('does not encrypt to expired key (expiration time subpacket on a direct-key signature)', async function() {
|
||||
const expiredKey = await openpgp.readKey({ armoredKey: expiredPublicKeyThroughDirectSignature });
|
||||
await expect(
|
||||
openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: expiredKey })
|
||||
).to.be.rejectedWith(/Primary key is expired/);
|
||||
});
|
||||
|
||||
it('uses AEAD when the encryption key prefs support it (SEIPv2', async function() {
|
||||
const v4PrivateKeyWithOCBPref = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
||||
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
||||
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||||
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
||||
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
||||
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
||||
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
||||
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||||
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
||||
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
||||
k0mXubZvyl4GBg==
|
||||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||||
const v6PrivateKeyWithOCBPref = await openpgp.readKey({ armoredKey: `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB
|
||||
exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ
|
||||
BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||||
2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh
|
||||
RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe
|
||||
7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/
|
||||
LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG
|
||||
GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6
|
||||
2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE
|
||||
M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr
|
||||
k0mXubZvyl4GBg==
|
||||
-----END PGP PRIVATE KEY BLOCK-----` });
|
||||
|
||||
const encrypted = await openpgp.encrypt({
|
||||
message: await openpgp.createMessage({ text: 'test' }),
|
||||
encryptionKeys: [v4PrivateKeyWithOCBPref, v6PrivateKeyWithOCBPref],
|
||||
format: 'object'
|
||||
});
|
||||
|
||||
const seipd = encrypted.packets[2];
|
||||
expect(seipd).to.be.instanceOf(openpgp.SymEncryptedIntegrityProtectedDataPacket);
|
||||
expect(seipd.version).to.equal(2);
|
||||
expect(seipd.aeadAlgorithm).to.equal(openpgp.enums.aead.ocb);
|
||||
});
|
||||
});
|
||||
|
||||
describe('encryptSessionKey - unit tests', function() {
|
||||
@ -2241,34 +2283,6 @@ VFBLG8uc9IiaKann/DYBAJcZNZHRSfpDoV2pUA5EAEi2MdjxkRysFQnYPRAu
|
||||
})).to.be.rejectedWith(/No encryption keys or passwords provided/);
|
||||
});
|
||||
|
||||
it('supports decrypting with argon2 s2k (memory-heavy params)', async function() {
|
||||
const passwords = 'password';
|
||||
// Test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#appendix-A.8.1
|
||||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||||
Comment: Encrypted using AES with 128-bit key
|
||||
Comment: Session key: 01FE16BBACFD1E7B78EF3B865187374F
|
||||
|
||||
wycEBwScUvg8J/leUNU1RA7N/zE2AQQVnlL8rSLPP5VlQsunlO+ECxHSPgGYGKY+
|
||||
YJz4u6F+DDlDBOr5NRQXt/KJIf4m4mOlKyC/uqLbpnLJZMnTq3o79GxBTdIdOzhH
|
||||
XfA3pqV4mTzF
|
||||
-----END PGP MESSAGE-----`;
|
||||
const expectedSessionKey = util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F');
|
||||
|
||||
try {
|
||||
const [decryptedSessionKey] = await openpgp.decryptSessionKeys({
|
||||
message: await openpgp.readMessage({ armoredMessage }),
|
||||
passwords
|
||||
});
|
||||
expect(decryptedSessionKey.data).to.deep.equal(expectedSessionKey);
|
||||
expect(decryptedSessionKey.algorithm).to.equal('aes128');
|
||||
} catch (err) {
|
||||
if (detectBrowser()) { // Expected to fail in the CI, especially in Browserstack
|
||||
expect(err.message).to.match(/Could not allocate required memory/);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// keep this after the 'memory-heavy' test to confirm that the Wasm module was successfully reloaded
|
||||
it('supports encrypting with argon2 s2k', async function() {
|
||||
const config = { s2kType: openpgp.enums.s2k.argon2 };
|
||||
@ -2349,6 +2363,33 @@ k0mXubZvyl4GBg==
|
||||
expect(sessionKeys).to.have.length(1);
|
||||
expect(sessionKeys[0].algorithm).to.equal(null); // PKESK v6 does not include the algo info
|
||||
});
|
||||
|
||||
it('supports decrypting with argon2 s2k (memory-heavy params)', async function() {
|
||||
const passwords = 'password';
|
||||
// Test vector from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#appendix-A.8.1
|
||||
const armoredMessage = `-----BEGIN PGP MESSAGE-----
|
||||
Comment: Encrypted using AES with 128-bit key
|
||||
Comment: Session key: 01FE16BBACFD1E7B78EF3B865187374F
|
||||
|
||||
wycEBwScUvg8J/leUNU1RA7N/zE2AQQVnlL8rSLPP5VlQsunlO+ECxHSPgGYGKY+
|
||||
YJz4u6F+DDlDBOr5NRQXt/KJIf4m4mOlKyC/uqLbpnLJZMnTq3o79GxBTdIdOzhH
|
||||
XfA3pqV4mTzF
|
||||
-----END PGP MESSAGE-----`;
|
||||
const expectedSessionKey = util.hexToUint8Array('01FE16BBACFD1E7B78EF3B865187374F');
|
||||
|
||||
try {
|
||||
const [decryptedSessionKey] = await openpgp.decryptSessionKeys({
|
||||
message: await openpgp.readMessage({ armoredMessage }),
|
||||
passwords
|
||||
});
|
||||
expect(decryptedSessionKey.data).to.deep.equal(expectedSessionKey);
|
||||
expect(decryptedSessionKey.algorithm).to.equal('aes128');
|
||||
} catch (err) {
|
||||
if (detectBrowser()) { // Expected to fail in the CI, especially in Browserstack
|
||||
expect(err.message).to.match(/Could not allocate required memory/);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('encrypt, decrypt, sign, verify - integration tests', function() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user