diff --git a/src/crypto/cfb.js b/src/crypto/cfb.js index 87e3dbcf..41e871cb 100644 --- a/src/crypto/cfb.js +++ b/src/crypto/cfb.js @@ -181,7 +181,7 @@ export default { cipherfn = new cipher[cipherfn](key); const block_size = cipherfn.blockSize; - let iblock = new Uint8Array(block_size); + const iblock = new Uint8Array(block_size); let ablock = new Uint8Array(block_size); let i; @@ -189,30 +189,10 @@ export default { let n; let text = new Uint8Array(ciphertext.length - block_size); - // initialisation vector - for (i = 0; i < block_size; i++) { - iblock[i] = 0; - } - - iblock = cipherfn.encrypt(iblock); - for (i = 0; i < block_size; i++) { - ablock[i] = ciphertext[i]; - iblock[i] ^= ablock[i]; - } - - ablock = cipherfn.encrypt(ablock); - - // test check octets - if (iblock[block_size - 2] !== (ablock[0] ^ ciphertext[block_size]) || - iblock[block_size - 1] !== (ablock[1] ^ ciphertext[block_size + 1])) { - throw new Error('CFB decrypt: invalid key'); - } - /* RFC4880: Tag 18 and Resync: * [...] Unlike the Symmetrically Encrypted Data Packet, no * special CFB resynchronization is done after encrypting this prefix * data. See "OpenPGP CFB Mode" below for more details. - */ j = 0; diff --git a/src/crypto/cmac.js b/src/crypto/cmac.js index b6d31ec7..d3675fbd 100644 --- a/src/crypto/cmac.js +++ b/src/crypto/cmac.js @@ -48,7 +48,7 @@ function rightXorMut(data, padding) { function pad(data, padding, padding2) { // if |M| in {n, 2n, 3n, ...} - if (data.length % blockLength === 0) { + if (data.length && data.length % blockLength === 0) { // then return M xor→ B, return rightXorMut(data, padding); } diff --git a/src/crypto/public_key/elliptic/curves.js b/src/crypto/public_key/elliptic/curves.js index f19f6662..2186ea9c 100644 --- a/src/crypto/public_key/elliptic/curves.js +++ b/src/crypto/public_key/elliptic/curves.js @@ -177,7 +177,14 @@ Curve.prototype.keyFromSecret = function (secret) { // Only for ed25519 }; Curve.prototype.keyFromPublic = function (pub) { - return new KeyPair(this, { pub: pub }); + const keyPair = new KeyPair(this, { pub: pub }); + if ( + this.keyType === enums.publicKey.ecdsa && + keyPair.keyPair.validate().result !== true + ) { + throw new Error('Invalid elliptic public key'); + } + return keyPair; }; Curve.prototype.genKeyPair = async function () { diff --git a/src/key.js b/src/key.js index b43450df..7b98420f 100644 --- a/src/key.js +++ b/src/key.js @@ -1451,6 +1451,19 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) { packetlist.push(secretKeyPacket); await Promise.all(options.userIds.map(async function(userId, index) { + function createdPreferredAlgos(algos, configAlgo) { + if (configAlgo) { // Not `uncompressed` / `plaintext` + 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 = new packet.Userid(); userIdPacket.format(userId); @@ -1462,26 +1475,30 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options) { signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm; signaturePacket.hashAlgorithm = await getPreferredHashAlgo(null, secretKeyPacket); signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data]; - signaturePacket.preferredSymmetricAlgorithms = []; - // prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support) - signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes256); - signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes128); - signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.aes192); - signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.cast5); - signaturePacket.preferredSymmetricAlgorithms.push(enums.symmetric.tripledes); + signaturePacket.preferredSymmetricAlgorithms = createdPreferredAlgos([ + // prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support) + enums.symmetric.aes256, + enums.symmetric.aes128, + enums.symmetric.aes192, + enums.symmetric.cast5, + enums.symmetric.tripledes + ], config.encryption_cipher); if (config.aead_protect && config.aead_protect_version === 4) { - signaturePacket.preferredAeadAlgorithms = []; - signaturePacket.preferredAeadAlgorithms.push(enums.aead.eax); - signaturePacket.preferredAeadAlgorithms.push(enums.aead.ocb); + signaturePacket.preferredAeadAlgorithms = createdPreferredAlgos([ + enums.aead.eax, + enums.aead.ocb + ], config.aead_mode); } - signaturePacket.preferredHashAlgorithms = []; - // prefer fast asm.js implementations (SHA-256). SHA-1 will not be secure much longer...move to bottom of list - signaturePacket.preferredHashAlgorithms.push(enums.hash.sha256); - signaturePacket.preferredHashAlgorithms.push(enums.hash.sha512); - signaturePacket.preferredHashAlgorithms.push(enums.hash.sha1); - signaturePacket.preferredCompressionAlgorithms = []; - signaturePacket.preferredCompressionAlgorithms.push(enums.compression.zlib); - signaturePacket.preferredCompressionAlgorithms.push(enums.compression.zip); + signaturePacket.preferredHashAlgorithms = createdPreferredAlgos([ + // prefer fast asm.js implementations (SHA-256). SHA-1 will not be secure much longer...move to bottom of list + enums.hash.sha256, + enums.hash.sha512, + enums.hash.sha1 + ], config.prefer_hash_algorithm); + signaturePacket.preferredCompressionAlgorithms = createdPreferredAlgos([ + enums.compression.zlib, + enums.compression.zip + ], config.compression); if (index === 0) { signaturePacket.isPrimaryUserID = true; } @@ -1690,7 +1707,7 @@ export async function getPreferredHashAlgo(key, keyPacket, date=new Date(), user */ export async function getPreferredAlgo(type, keys, date=new Date(), userId={}) { const prefProperty = type === 'symmetric' ? 'preferredSymmetricAlgorithms' : 'preferredAeadAlgorithms'; - const defaultAlgo = type === 'symmetric' ? config.encryption_cipher : config.aead_mode; + const defaultAlgo = type === 'symmetric' ? enums.symmetric.aes128 : enums.aead.eax; const prioMap = {}; await Promise.all(keys.map(async function(key) { const primaryUser = await key.getPrimaryUser(date, userId); diff --git a/src/message.js b/src/message.js index d8818616..5bdff7ca 100644 --- a/src/message.js +++ b/src/message.js @@ -153,6 +153,7 @@ Message.prototype.decrypt = async function(privateKeys, passwords, sessionKeys, Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) { let keyPackets = []; + let exception; if (passwords) { const symESKeyPacketlist = this.packets.filterByTag(enums.packet.symEncryptedSessionKey); if (!symESKeyPacketlist) { @@ -181,23 +182,36 @@ Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) { throw new Error('No public key encrypted session key packet found.'); } await Promise.all(pkESKeyPacketlist.map(async function(keyPacket) { - const privateKeyPackets = new packet.List(); - privateKeys.forEach(privateKey => { - privateKeyPackets.concat(privateKey.getKeys(keyPacket.publicKeyId).map(key => key.keyPacket)); - }); - await Promise.all(privateKeyPackets.map(async function(privateKeyPacket) { - if (!privateKeyPacket) { - return; - } - if (!privateKeyPacket.isDecrypted()) { - throw new Error('Private key is not decrypted.'); - } - try { - await keyPacket.decrypt(privateKeyPacket); - keyPackets.push(keyPacket); - } catch (err) { - util.print_debug_error(err); + await Promise.all(privateKeys.map(async function(privateKey) { + const primaryUser = await privateKey.getPrimaryUser(); // TODO: Pass userId from somewhere. + let algos = [ + enums.symmetric.aes256, // Old OpenPGP.js default fallback + enums.symmetric.aes128, // RFC4880bis fallback + enums.symmetric.tripledes // RFC4880 fallback + ]; + if (primaryUser && primaryUser.selfCertification.preferredSymmetricAlgorithms) { + algos = algos.concat(primaryUser.selfCertification.preferredSymmetricAlgorithms); } + + const privateKeyPackets = privateKey.getKeys(keyPacket.publicKeyId).map(key => key.keyPacket); + await Promise.all(privateKeyPackets.map(async function(privateKeyPacket) { + if (!privateKeyPacket) { + return; + } + if (!privateKeyPacket.isDecrypted()) { + throw new Error('Private key is not decrypted.'); + } + try { + await keyPacket.decrypt(privateKeyPacket); + if (!algos.includes(enums.write(enums.symmetric, keyPacket.sessionKeyAlgorithm))) { + throw new Error('A non-preferred symmetric algorithm was used.'); + } + keyPackets.push(keyPacket); + } catch (err) { + util.print_debug_error(err); + exception = err; + } + })); })); stream.cancel(keyPacket.encrypted); // Don't keep copy of encrypted data in memory. keyPacket.encrypted = null; @@ -222,7 +236,7 @@ Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) { return keyPackets.map(packet => ({ data: packet.sessionKey, algorithm: packet.sessionKeyAlgorithm })); } - throw new Error('Session key decryption failed.'); + throw exception || new Error('Session key decryption failed.'); }; /** @@ -230,7 +244,8 @@ Message.prototype.decryptSessionKeys = async function(privateKeys, passwords) { * @returns {(Uint8Array|null)} literal body of the message as Uint8Array */ Message.prototype.getLiteralData = function() { - const literal = this.packets.findPacket(enums.packet.literal); + const msg = this.unwrapCompressed(); + const literal = msg.packets.findPacket(enums.packet.literal); return (literal && literal.getBytes()) || null; }; @@ -239,7 +254,8 @@ Message.prototype.getLiteralData = function() { * @returns {(String|null)} filename of literal data packet as string */ Message.prototype.getFilename = function() { - const literal = this.packets.findPacket(enums.packet.literal); + const msg = this.unwrapCompressed(); + const literal = msg.packets.findPacket(enums.packet.literal); return (literal && literal.getFilename()) || null; }; @@ -248,7 +264,8 @@ Message.prototype.getFilename = function() { * @returns {(String|null)} literal body of the message interpreted as text */ Message.prototype.getText = function() { - const literal = this.packets.findPacket(enums.packet.literal); + const msg = this.unwrapCompressed(); + const literal = msg.packets.findPacket(enums.packet.literal); if (literal) { return literal.getText(); } diff --git a/src/packet/packetlist.js b/src/packet/packetlist.js index b56c2cd2..03f8c7da 100644 --- a/src/packet/packetlist.js +++ b/src/packet/packetlist.js @@ -168,24 +168,10 @@ List.prototype.filterByTag = function (...args) { /** * Traverses packet tree and returns first matching packet * @param {module:enums.packet} type The packet type - * @returns {module:packet/packet|null} + * @returns {module:packet/packet|undefined} */ List.prototype.findPacket = function (type) { - const packetlist = this.filterByTag(type); - if (packetlist.length) { - return packetlist[0]; - } - let found = null; - for (let i = 0; i < this.length; i++) { - if (this[i].packets.length) { - found = this[i].packets.findPacket(type); - if (found) { - return found; - } - } - } - - return null; + return this.find(packet => packet.tag === type); }; /** diff --git a/src/packet/public_key.js b/src/packet/public_key.js index ca43ea05..2d6c6895 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -62,6 +62,11 @@ function PublicKey(date=new Date()) { * @type {Date} */ this.created = util.normalizeDate(date); + /** + * Public key algorithm. + * @type {String} + */ + this.algorithm = null; /** * Algorithm specific params * @type {Array} diff --git a/src/packet/public_key_encrypted_session_key.js b/src/packet/public_key_encrypted_session_key.js index 260497da..fc93e430 100644 --- a/src/packet/public_key_encrypted_session_key.js +++ b/src/packet/public_key_encrypted_session_key.js @@ -52,7 +52,10 @@ function PublicKeyEncryptedSessionKey() { this.version = 3; this.publicKeyId = new type_keyid(); + this.publicKeyAlgorithm = null; + this.sessionKey = null; + this.sessionKeyAlgorithm = null; /** @type {Array} */ this.encrypted = []; @@ -150,7 +153,7 @@ PublicKeyEncryptedSessionKey.prototype.decrypt = async function (key) { key = util.str_to_Uint8Array(decoded.substring(1, decoded.length - 2)); if (!util.equalsUint8Array(checksum, util.write_checksum(key))) { - throw new Error('Checksum mismatch'); + throw new Error('Decryption error'); } else { this.sessionKey = key; this.sessionKeyAlgorithm = enums.read(enums.symmetric, decoded.charCodeAt(0)); diff --git a/src/packet/signature.js b/src/packet/signature.js index 0faf2875..bd78c8f3 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -666,6 +666,10 @@ Signature.prototype.verify = async function (key, signatureType, data) { const publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm); const hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm); + if (publicKeyAlgorithm !== enums.write(enums.publicKey, key.algorithm)) { + throw new Error('Public key algorithm used to sign signature does not match issuer key algorithm.'); + } + let toHash; let hash; if (this.hashed) { diff --git a/test/crypto/elliptic.js b/test/crypto/elliptic.js index 9e1b72c8..f4852b89 100644 --- a/test/crypto/elliptic.js +++ b/test/crypto/elliptic.js @@ -223,7 +223,17 @@ describe('Elliptic Curve Cryptography', async function () { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]); - const secp256k1_dummy_point = new Uint8Array([ + const secp256k1_point = new Uint8Array([ + 0x04, + 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, + 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, + 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, + 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, + 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, + 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8, + 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, + 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8]); + const secp256k1_invalid_point = new Uint8Array([ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -233,7 +243,7 @@ describe('Elliptic Curve Cryptography', async function () { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - const secp256k1_invalid_point = new Uint8Array([ + const secp256k1_invalid_point_format = new Uint8Array([ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -255,13 +265,18 @@ describe('Elliptic Curve Cryptography', async function () { 'secp256k1', 8, [], [], [], [] )).to.be.rejectedWith(Error, /Unknown point format/), expect(verify_signature( - 'secp256k1', 8, [], [], [], secp256k1_invalid_point + 'secp256k1', 8, [], [], [], secp256k1_invalid_point_format )).to.be.rejectedWith(Error, /Unknown point format/) ]); }); + it('Invalid point', function (done) { + expect(verify_signature( + 'secp256k1', 8, [], [], [], secp256k1_invalid_point + )).to.be.rejectedWith(Error, /Invalid elliptic public key/).notify(done); + }); it('Invalid signature', function (done) { expect(verify_signature( - 'secp256k1', 8, [], [], [], secp256k1_dummy_point + 'secp256k1', 8, [], [], [], secp256k1_point )).to.eventually.be.false.notify(done); }); @@ -331,11 +346,21 @@ describe('Elliptic Curve Cryptography', async function () { ]); const secp256k1_point = new Uint8Array([ 0x04, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, + 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, + 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, + 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, + 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, + 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8, + 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, + 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8]); + const secp256k1_invalid_point = new Uint8Array([ + 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); @@ -354,6 +379,11 @@ describe('Elliptic Curve Cryptography', async function () { 'secp256k1', 2, 7, [], [], [], [] )).to.be.rejectedWith(Error, /Unknown point format/).notify(done); }); + it('Invalid elliptic public key', function (done) { + expect(decrypt_message( + 'secp256k1', 2, 7, secp256k1_value, secp256k1_invalid_point, secp256k1_data, [] + )).to.be.rejectedWith(Error, /Invalid elliptic public key/).notify(done); + }); it('Invalid key data integrity', function (done) { expect(decrypt_message( 'secp256k1', 2, 7, secp256k1_value, secp256k1_point, secp256k1_data, [] diff --git a/test/general/key.js b/test/general/key.js index a2ce51a3..bc84ba4f 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -1357,6 +1357,49 @@ function versionSpecificTests() { }); }); + it('Preferences of generated key - with config values', async function() { + const encryption_cipherVal = openpgp.config.encryption_cipher; + const prefer_hash_algorithmVal = openpgp.config.prefer_hash_algorithm; + const compressionVal = openpgp.config.compression; + const aead_modeVal = openpgp.config.aead_mode; + openpgp.config.encryption_cipher = openpgp.enums.symmetric.aes192; + openpgp.config.prefer_hash_algorithm = openpgp.enums.hash.sha384; + openpgp.config.compression = openpgp.enums.compression.zlib; + openpgp.config.aead_mode = openpgp.enums.aead.experimental_gcm; + + const testPref = function(key) { + // key flags + const keyFlags = openpgp.enums.keyFlags; + expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.certify_keys).to.equal(keyFlags.certify_keys); + expect(key.users[0].selfCertifications[0].keyFlags[0] & keyFlags.sign_data).to.equal(keyFlags.sign_data); + expect(key.subKeys[0].bindingSignatures[0].keyFlags[0] & keyFlags.encrypt_communication).to.equal(keyFlags.encrypt_communication); + 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.aes192, sym.aes256, sym.aes128, sym.cast5, sym.tripledes]); + 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.experimental_gcm, aead.eax, aead.ocb]); + } + const hash = openpgp.enums.hash; + expect(key.users[0].selfCertifications[0].preferredHashAlgorithms).to.eql([hash.sha384, 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 && 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 + try { + const key = await openpgp.generateKey(opt); + testPref(key.key); + testPref((await openpgp.key.readArmored(key.publicKeyArmored)).keys[0]); + } finally { + openpgp.config.encryption_cipher = encryption_cipherVal; + openpgp.config.prefer_hash_algorithm = prefer_hash_algorithmVal; + openpgp.config.compression = compressionVal; + openpgp.config.aead_mode = aead_modeVal; + } + }); + it('Generated key is not unlocked by default', function() { const opt = {numBits: 512, userIds: 'test ', passphrase: '123'}; if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys @@ -2147,14 +2190,14 @@ describe('Key', function() { expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes256); }); - it("getPreferredAlgo('symmetric') - two key - AES128", async function() { + it("getPreferredAlgo('symmetric') - two key - AES192", async function() { const keys = (await openpgp.key.readArmored(twoKeys)).keys; const key1 = keys[0]; const key2 = keys[1]; const primaryUser = await key2.getPrimaryUser(); - primaryUser.selfCertification.preferredSymmetricAlgorithms = [6,7,3]; + primaryUser.selfCertification.preferredSymmetricAlgorithms = [6,8,3]; const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1, key2]); - expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128); + expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes192); }); it("getPreferredAlgo('symmetric') - two key - one without pref", async function() { @@ -2164,7 +2207,7 @@ describe('Key', function() { const primaryUser = await key2.getPrimaryUser(); primaryUser.selfCertification.preferredSymmetricAlgorithms = null; const prefAlgo = await openpgp.key.getPreferredAlgo('symmetric', [key1, key2]); - expect(prefAlgo).to.equal(openpgp.config.encryption_cipher); + expect(prefAlgo).to.equal(openpgp.enums.symmetric.aes128); }); it("getPreferredAlgo('aead') - one key - OCB", async function() { @@ -2188,7 +2231,7 @@ describe('Key', function() { const primaryUser2 = await key2.getPrimaryUser(); primaryUser2.selfCertification.features = [7]; // Monkey-patch AEAD feature flag const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]); - expect(prefAlgo).to.equal(openpgp.config.aead_mode); + expect(prefAlgo).to.equal(openpgp.enums.aead.eax); const supported = await openpgp.key.isAeadSupported([key1, key2]); expect(supported).to.be.true; }); @@ -2201,7 +2244,7 @@ describe('Key', function() { primaryUser.selfCertification.features = [7]; // Monkey-patch AEAD feature flag primaryUser.selfCertification.preferredAeadAlgorithms = [2,1]; const prefAlgo = await openpgp.key.getPreferredAlgo('aead', [key1, key2]); - expect(prefAlgo).to.equal(openpgp.config.aead_mode); + expect(prefAlgo).to.equal(openpgp.enums.aead.eax); const supported = await openpgp.key.isAeadSupported([key1, key2]); expect(supported).to.be.false; }); diff --git a/test/security/index.js b/test/security/index.js index 5ca983e1..d515963f 100644 --- a/test/security/index.js +++ b/test/security/index.js @@ -2,4 +2,5 @@ describe('Security', function () { require('./message_signature_bypass'); require('./unsigned_subpackets'); require('./subkey_trust'); + require('./preferred_algo_mismatch'); }); diff --git a/test/security/preferred_algo_mismatch.js b/test/security/preferred_algo_mismatch.js new file mode 100644 index 00000000..74cb644d --- /dev/null +++ b/test/security/preferred_algo_mismatch.js @@ -0,0 +1,49 @@ +const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp'); + +const { key, cleartext, enums, packet: { List, Signature } } = openpgp; + +const chai = require('chai'); +chai.use(require('chai-as-promised')); + +const expect = chai.expect; + +const messageArmor = `-----BEGIN PGP MESSAGE----- +Version: OpenPGP.js VERSION +Comment: https://openpgpjs.org + +wYwD3eCUoDfD5yoBA/4rhxaaw+E2ma+LdmLVDBRqxglhIgnM6EgNxzf8J5Ty +ecQBLOf3BjjC72mJ9RqMmvQ16aG4EXXDAUmCP1sBLj+b7V1t4keeyTn+2nXu +7Wgu2yq9CvZahRLsayt3y8VodZwTi3K/+gmx1f8EhdLPONQgGkYAqZ3Tyyd0 +KF3pknplvdI+AXqRs0n2vVr89oIdmQPJFSHEoJtltbSNxhwShdzDvOor2FKJ +vhGWNysion2aBg0fIbgDUKeXKp8YN44LDTk= +=RYrv +-----END PGP MESSAGE-----`; + +const privateKeyArmor = `-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: OpenPGP.js VERSION +Comment: https://openpgpjs.org + +xcEYBFvbA08BBACl8U5VEY7TNq1PAzwU0f3soqNfFpKtNFt+LY3q5sasouJ7 +zE4/TPYrAaAoM5/yOjfvbfJP5myBUCtkdtIRIY2iP2uOPhfaly8U+zH25Qnq +bmgLfvu4ytPAPrKZF8f98cIeJmHD81SPRgDMuB2U9wwgN6stgVBBCUS+lu/L +/4pyuwARAQABAAP+Jz6BIvcrCuJ0bCo8rEPZRHxWHKfO+m1Wcem+FV6Mf8lp +vJNdsfS2hwc0ZC2JVxTTo6kh1CmPYamfCXxcQ7bmsqWkkq/6d17zKE6BqE/n +spW7qTnZ14VPC0iPrBetAWRlCk+m0cEkRnBxqPOVBNd6VPcZyM7GUOGf/kiw +AsHf+nECANkN1tsqLJ3+pH2MRouF7yHevQ9OGg+rwetBO2a8avvcsAuoFjVw +hERpkHv/PQjKAE7KcBzqLLad0QbrQW+sUcMCAMO3to0tSBJrNA9YkrViT76I +siiahSB/FC9JlO+T46xncRleZeBHc0zoVAP+W/PjRo2CR4ydtwjjalrxcKX9 +E6kCALfDyhkRNzZLxg2XOGDWyeXqe80VWnMBqTZK73nZlACRcUoXuvjRc15Q +K2c3/nZ7LMyQidj8XsTq4sz1zfWz4Cejj80cVGVzdCBVc2VyIDx0ZXN0QGV4 +YW1wbGUuY29tPsK1BBABCAApBQJb2wNPAgsJCRDd4JSgN8PnKgQVCAoCAxYC +AQIZAQIbDwIeBwMiAQIAABGjA/4y6HjthMU03AC3bIUyYPv6EJc9czS5wysa +5rKuNhzka0Klb0INcX1YZ8usPIIl1rtr8f8xxCdSiqhJpn+uqIPVROHi0XLG +ej3gSJM5i1lIt1jxyJlvVI/7W0vzuE85KDzGXQFNFyO/T9D7T1SDHnS8KbBh +EnxUPL95HuMKoVkf4w== +=oopr +-----END PGP PRIVATE KEY BLOCK-----`; + +it('Does not accept message encrypted with algo not mentioned in preferred algorithms', async function() { + const message = await openpgp.message.readArmored(messageArmor); + const privKey = (await openpgp.key.readArmored(privateKeyArmor)).keys[0]; + await expect(openpgp.decrypt({ message, privateKeys: [privKey] })).to.be.rejectedWith('A non-preferred symmetric algorithm was used.'); +});