From 28dbbadcff32c3d178c7f7df815f40d7c9f5533a Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Tue, 10 Apr 2018 16:44:52 +0200 Subject: [PATCH] Add config.aead_protect_version option --- src/config/config.js | 9 +++++++ src/key.js | 4 +-- src/packet/public_key.js | 2 +- src/packet/sym_encrypted_aead_protected.js | 10 ++++---- src/packet/sym_encrypted_session_key.js | 2 +- test/general/key.js | 10 +++++--- test/general/openpgp.js | 9 +++++-- test/general/packet.js | 30 +++++++++++++++++----- 8 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index e2cfef90..5446b291 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -51,6 +51,15 @@ export default { * @property {Boolean} aead_protect */ aead_protect: false, + /** + * Use Authenticated Encryption with Additional Data (AEAD) protection for symmetric encryption. + * 0 means we implement a variant of {@link https://tools.ietf.org/html/draft-ford-openpgp-format-00|this IETF draft}. + * 4 means we implement {@link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-04|RFC4880bis-04}. + * Only has an effect when aead_protect is set to true. + * @memberof module:config + * @property {Integer} aead_protect_version + */ + aead_protect_version: 0, /** * Default Authenticated Encryption with Additional Data (AEAD) encryption mode * Only has an effect when aead_protect is set to true. diff --git a/src/key.js b/src/key.js index 7e4dfe42..30b94b4b 100644 --- a/src/key.js +++ b/src/key.js @@ -1261,7 +1261,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) { signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes192); signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.cast5); signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.tripledes); - if (config.aead_protect === 'draft04') { + if (config.aead_protect && config.aead_protect_version === 4) { signaturePacket.preferredAeadAlgorithms = []; signaturePacket.preferredAeadAlgorithms.push(enums.aead.eax); signaturePacket.preferredAeadAlgorithms.push(enums.aead.ocb); @@ -1281,7 +1281,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) { signaturePacket.features = [0]; signaturePacket.features[0] |= enums.features.modification_detection; } - if (config.aead_protect === 'draft04') { + if (config.aead_protect && config.aead_protect_version === 4) { signaturePacket.features || (signaturePacket.features = [0]); signaturePacket.features[0] |= enums.features.aead; signaturePacket.features[0] |= enums.features.v5_keys; diff --git a/src/packet/public_key.js b/src/packet/public_key.js index f76e16fa..491d3ddd 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -54,7 +54,7 @@ function PublicKey(date=new Date()) { * Packet version * @type {Integer} */ - this.version = config.aead_protect === 'draft04' ? 5 : 4; + this.version = config.aead_protect && config.aead_protect_version === 4 ? 5 : 4; /** * Key creation date. * @type {Date} diff --git a/src/packet/sym_encrypted_aead_protected.js b/src/packet/sym_encrypted_aead_protected.js index 766a3bb8..e5268cc5 100644 --- a/src/packet/sym_encrypted_aead_protected.js +++ b/src/packet/sym_encrypted_aead_protected.js @@ -61,7 +61,7 @@ SymEncryptedAEADProtected.prototype.read = function (bytes) { throw new Error('Invalid packet version.'); } offset++; - if (config.aead_protect === 'draft04') { + if (config.aead_protect_version === 4) { this.cipherAlgo = bytes[offset++]; this.aeadAlgo = bytes[offset++]; this.chunkSizeByte = bytes[offset++]; @@ -79,7 +79,7 @@ SymEncryptedAEADProtected.prototype.read = function (bytes) { * @returns {Uint8Array} The encrypted payload */ SymEncryptedAEADProtected.prototype.write = function () { - if (config.aead_protect === 'draft04') { + if (config.aead_protect_version === 4) { return util.concatUint8Array([new Uint8Array([this.version, this.cipherAlgo, this.aeadAlgo, this.chunkSizeByte]), this.iv, this.encrypted]); } return util.concatUint8Array([new Uint8Array([this.version]), this.iv, this.encrypted]); @@ -94,7 +94,7 @@ SymEncryptedAEADProtected.prototype.write = function () { */ SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key) { const mode = crypto[enums.read(enums.aead, this.aeadAlgo)]; - if (config.aead_protect === 'draft04') { + if (config.aead_protect_version === 4) { const cipher = enums.read(enums.symmetric, this.cipherAlgo); let data = this.encrypted.subarray(0, this.encrypted.length - mode.blockLength); const authTag = this.encrypted.subarray(this.encrypted.length - mode.blockLength); @@ -132,11 +132,11 @@ SymEncryptedAEADProtected.prototype.decrypt = async function (sessionKeyAlgorith * @async */ SymEncryptedAEADProtected.prototype.encrypt = async function (sessionKeyAlgorithm, key) { - this.aeadAlgo = config.aead_protect === 'draft04' ? enums.write(enums.aead, this.aeadAlgorithm) : enums.aead.gcm; + this.aeadAlgo = config.aead_protect_version === 4 ? enums.write(enums.aead, this.aeadAlgorithm) : enums.aead.gcm; const mode = crypto[enums.read(enums.aead, this.aeadAlgo)]; this.iv = await crypto.random.getRandomBytes(mode.ivLength); // generate new random IV let data = this.packets.write(); - if (config.aead_protect === 'draft04') { + if (config.aead_protect_version === 4) { this.cipherAlgo = enums.write(enums.symmetric, sessionKeyAlgorithm); this.chunkSizeByte = config.aead_chunk_size_byte; const chunkSize = 2 ** (this.chunkSizeByte + 6); // ((uint64_t)1 << (c + 6)) diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js index 9e4d6de0..275f6431 100644 --- a/src/packet/sym_encrypted_session_key.js +++ b/src/packet/sym_encrypted_session_key.js @@ -49,7 +49,7 @@ import util from '../util'; */ function SymEncryptedSessionKey() { this.tag = enums.packet.symEncryptedSessionKey; - this.version = config.aead_protect === 'draft04' ? 5 : 4; + this.version = config.aead_protect && config.aead_protect_version === 4 ? 5 : 4; this.sessionKey = null; this.sessionKeyEncryptionAlgorithm = null; this.sessionKeyAlgorithm = 'aes256'; diff --git a/test/general/key.js b/test/general/key.js index ec7a6e9b..1e51bc37 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -10,12 +10,16 @@ describe('Key', function() { describe('V5', function() { let aead_protectVal; + let aead_protect_versionVal; beforeEach(function() { aead_protectVal = openpgp.config.aead_protect; - openpgp.config.aead_protect = 'draft04'; + aead_protect_versionVal = openpgp.config.aead_protect_version; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; }); afterEach(function() { openpgp.config.aead_protect = aead_protectVal; + openpgp.config.aead_protect_version = aead_protect_versionVal; }); tests(); @@ -1220,7 +1224,7 @@ p92yZgB3r2+f6/GIe2+7 expect(key.subKeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encrypt_storage).to.equal(keyFlags.encrypt_storage); const sym = openpgp.enums.symmetric; expect(key.users[0].selfCertifications[0].preferredSymmetricAlgorithms).to.eql([sym.aes256, sym.aes128, sym.aes192, sym.cast5, sym.tripledes]); - if (openpgp.config.aead_protect === 'draft04') { + if (openpgp.config.aead_protect && openpgp.config.aead_protect_version === 4) { const aead = openpgp.enums.aead; expect(key.users[0].selfCertifications[0].preferredAeadAlgorithms).to.eql([aead.eax, aead.ocb]); } @@ -1228,7 +1232,7 @@ p92yZgB3r2+f6/GIe2+7 expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha256, hash.sha512, hash.sha1]); const compr = openpgp.enums.compression; expect(key.users[0].selfCertifications[0].preferredCompressionAlgorithms).to.eql([compr.zlib, compr.zip]); - expect(key.users[0].selfCertifications[0].features).to.eql(openpgp.config.aead_protect === 'draft04' ? [7] : [1]); + expect(key.users[0].selfCertifications[0].features).to.eql(openpgp.config.aead_protect && openpgp.config.aead_protect_version === 4 ? [7] : [1]); }; const opt = {numBits: 512, userIds: 'test ', passphrase: 'hello'}; if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys diff --git a/test/general/openpgp.js b/test/general/openpgp.js index e4f94bd2..6ad80330 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -597,6 +597,7 @@ describe('OpenPGP.js public api tests', function() { let zero_copyVal; let use_nativeVal; let aead_protectVal; + let aead_protect_versionVal; beforeEach(function(done) { publicKey = openpgp.key.readArmored(pub_key); @@ -620,6 +621,7 @@ describe('OpenPGP.js public api tests', function() { zero_copyVal = openpgp.config.zero_copy; use_nativeVal = openpgp.config.use_native; aead_protectVal = openpgp.config.aead_protect; + aead_protect_versionVal = openpgp.config.aead_protect_version; done(); }); @@ -627,6 +629,7 @@ describe('OpenPGP.js public api tests', function() { openpgp.config.zero_copy = zero_copyVal; openpgp.config.use_native = use_nativeVal; openpgp.config.aead_protect = aead_protectVal; + openpgp.config.aead_protect_version = aead_protect_versionVal; }); it('Decrypting key with wrong passphrase rejected', async function () { @@ -671,7 +674,8 @@ describe('OpenPGP.js public api tests', function() { if: true, beforeEach: function() { openpgp.config.use_native = false; - openpgp.config.aead_protect = 'draft04'; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; } }); @@ -679,7 +683,8 @@ describe('OpenPGP.js public api tests', function() { if: openpgp.util.getWebCryptoAll() || openpgp.util.getNodeCrypto(), beforeEach: function() { openpgp.config.use_native = true; - openpgp.config.aead_protect = 'draft04'; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; } }); diff --git a/test/general/packet.js b/test/general/packet.js index 4f951e8c..32ba3b25 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -144,7 +144,9 @@ describe("Packet", function() { it('Sym. encrypted AEAD protected packet (draft04)', function() { let aead_protectVal = openpgp.config.aead_protect; - openpgp.config.aead_protect = 'draft04'; + let aead_protect_versionVal = openpgp.config.aead_protect_version; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; const key = new Uint8Array([1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2]); const algo = 'aes256'; @@ -166,6 +168,7 @@ describe("Packet", function() { expect(msg2[0].packets[0].data).to.deep.equal(literal.data); }).finally(function() { openpgp.config.aead_protect = aead_protectVal; + openpgp.config.aead_protect_version = aead_protect_versionVal; }); }); @@ -181,8 +184,10 @@ describe("Packet", function() { `.replace(/\s+/g, '')); let aead_protectVal = openpgp.config.aead_protect; + let aead_protect_versionVal = openpgp.config.aead_protect_version; let aead_chunk_size_byteVal = openpgp.config.aead_chunk_size_byte; - openpgp.config.aead_protect = 'draft04'; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; openpgp.config.aead_chunk_size_byte = 14; const iv = openpgp.util.hex_to_Uint8Array('b7 32 37 9f 73 c4 92 8d e2 5f ac fe 65 17 ec 10'.replace(/\s+/g, '')); @@ -212,6 +217,7 @@ describe("Packet", function() { expect(msg2[0].packets[0].data).to.deep.equal(literal.data); }).finally(function() { openpgp.config.aead_protect = aead_protectVal; + openpgp.config.aead_protect_version = aead_protect_versionVal; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteVal; randomBytesStub.restore(); }); @@ -417,7 +423,9 @@ describe("Packet", function() { it('Sym. encrypted session key reading/writing (draft04)', async function() { let aead_protectVal = openpgp.config.aead_protect; - openpgp.config.aead_protect = 'draft04'; + let aead_protect_versionVal = openpgp.config.aead_protect_version; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; try { const passphrase = 'hello'; @@ -450,6 +458,7 @@ describe("Packet", function() { expect(stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data)); } finally { openpgp.config.aead_protect = aead_protectVal; + openpgp.config.aead_protect_version = aead_protect_versionVal; } }); @@ -457,9 +466,11 @@ describe("Packet", function() { // From https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b20923/back.mkd#sample-aead-eax-encryption-and-decryption let aead_protectVal = openpgp.config.aead_protect; + let aead_protect_versionVal = openpgp.config.aead_protect_version; let aead_chunk_size_byteVal = openpgp.config.aead_chunk_size_byte; let s2k_iteration_count_byteVal = openpgp.config.s2k_iteration_count_byte; - openpgp.config.aead_protect = 'draft04'; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; openpgp.config.aead_chunk_size_byte = 14; openpgp.config.s2k_iteration_count_byte = 0x90; @@ -522,6 +533,7 @@ describe("Packet", function() { expect(stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data)); } finally { openpgp.config.aead_protect = aead_protectVal; + openpgp.config.aead_protect_version = aead_protect_versionVal; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteVal; openpgp.config.s2k_iteration_count_byte = s2k_iteration_count_byteVal; randomBytesStub.restore(); @@ -532,9 +544,11 @@ describe("Packet", function() { // From https://gitlab.com/openpgp-wg/rfc4880bis/blob/00b20923/back.mkd#sample-aead-ocb-encryption-and-decryption let aead_protectVal = openpgp.config.aead_protect; + let aead_protect_versionVal = openpgp.config.aead_protect_version; let aead_chunk_size_byteVal = openpgp.config.aead_chunk_size_byte; let s2k_iteration_count_byteVal = openpgp.config.s2k_iteration_count_byte; - openpgp.config.aead_protect = 'draft04'; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; openpgp.config.aead_chunk_size_byte = 14; openpgp.config.s2k_iteration_count_byte = 0x90; @@ -598,6 +612,7 @@ describe("Packet", function() { expect(stringify(msg2[1].packets[0].data)).to.equal(stringify(literal.data)); } finally { openpgp.config.aead_protect = aead_protectVal; + openpgp.config.aead_protect_version = aead_protect_versionVal; openpgp.config.aead_chunk_size_byte = aead_chunk_size_byteVal; openpgp.config.s2k_iteration_count_byte = s2k_iteration_count_byteVal; randomBytesStub.restore(); @@ -715,7 +730,9 @@ describe("Packet", function() { it('Writing and encryption of a secret key packet. (draft04)', function() { let aead_protectVal = openpgp.config.aead_protect; - openpgp.config.aead_protect = 'draft04'; + let aead_protect_versionVal = openpgp.config.aead_protect_version; + openpgp.config.aead_protect = true; + openpgp.config.aead_protect_version = 4; const key = new openpgp.packet.List(); key.push(new openpgp.packet.SecretKey()); @@ -742,6 +759,7 @@ describe("Packet", function() { expect(key[0].params.toString()).to.equal(key2[0].params.toString()); }).finally(function() { openpgp.config.aead_protect = aead_protectVal; + openpgp.config.aead_protect_version = aead_protect_versionVal; }); });