commit
b1b19946d8
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 () {
|
||||
|
|
55
src/key.js
55
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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<Object>}
|
||||
|
|
|
@ -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<module:type/mpi>} */
|
||||
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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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, []
|
||||
|
|
|
@ -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 <a@b.com>', 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 <a@b.com>', 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;
|
||||
});
|
||||
|
|
|
@ -2,4 +2,5 @@ describe('Security', function () {
|
|||
require('./message_signature_bypass');
|
||||
require('./unsigned_subpackets');
|
||||
require('./subkey_trust');
|
||||
require('./preferred_algo_mismatch');
|
||||
});
|
||||
|
|
49
test/security/preferred_algo_mismatch.js
Normal file
49
test/security/preferred_algo_mismatch.js
Normal file
|
@ -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.');
|
||||
});
|
Loading…
Reference in New Issue
Block a user