rename decryptSessionKey to decryptSessionKeys, return only unique session keys
This commit is contained in:
parent
210ec26ed3
commit
602bbb707d
|
@ -47,7 +47,7 @@ export default {
|
||||||
zero_copy: false, // use transferable objects between the Web Worker and main thread
|
zero_copy: false, // use transferable objects between the Web Worker and main thread
|
||||||
debug: false,
|
debug: false,
|
||||||
tolerant: true, // ignore unsupported/unrecognizable packets instead of throwing an error,
|
tolerant: true, // ignore unsupported/unrecognizable packets instead of throwing an error,
|
||||||
password_collision_check: false, // work-around for rare GPG decryption bug with encrypting with multiple passwords
|
password_collision_check: false, // work-around for rare GPG decryption bug when encrypting with multiple passwords. Slower and slightly less secure
|
||||||
show_version: true,
|
show_version: true,
|
||||||
show_comment: true,
|
show_comment: true,
|
||||||
versionstring: "OpenPGP.js VERSION",
|
versionstring: "OpenPGP.js VERSION",
|
||||||
|
|
|
@ -22,7 +22,7 @@ export default openpgp;
|
||||||
export {
|
export {
|
||||||
encrypt, decrypt, sign, verify,
|
encrypt, decrypt, sign, verify,
|
||||||
generateKey, reformatKey, decryptKey,
|
generateKey, reformatKey, decryptKey,
|
||||||
encryptSessionKey, decryptSessionKey,
|
encryptSessionKey, decryptSessionKeys,
|
||||||
initWorker, getWorker, destroyWorker
|
initWorker, getWorker, destroyWorker
|
||||||
} from './openpgp';
|
} from './openpgp';
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ Message.prototype.getSigningKeyIds = function() {
|
||||||
* @return {Message} new message with decrypted content
|
* @return {Message} new message with decrypted content
|
||||||
*/
|
*/
|
||||||
Message.prototype.decrypt = async function(privateKey, sessionKey, password) {
|
Message.prototype.decrypt = async function(privateKey, sessionKey, password) {
|
||||||
let keyObjs = sessionKey || await this.decryptSessionKey(privateKey, password);
|
let keyObjs = sessionKey || await this.decryptSessionKeys(privateKey, password);
|
||||||
if (!util.isArray(keyObjs)) {
|
if (!util.isArray(keyObjs)) {
|
||||||
keyObjs = [keyObjs];
|
keyObjs = [keyObjs];
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ Message.prototype.decrypt = async function(privateKey, sessionKey, password) {
|
||||||
* @return {Array} array of object with potential sessionKey, algorithm pairs in the form:
|
* @return {Array} array of object with potential sessionKey, algorithm pairs in the form:
|
||||||
* { data:Uint8Array, algorithm:String }
|
* { data:Uint8Array, algorithm:String }
|
||||||
*/
|
*/
|
||||||
Message.prototype.decryptSessionKey = function(privateKey, password) {
|
Message.prototype.decryptSessionKeys = function(privateKey, password) {
|
||||||
var keyPackets = [];
|
var keyPackets = [];
|
||||||
return Promise.resolve().then(async () => {
|
return Promise.resolve().then(async () => {
|
||||||
if (password) {
|
if (password) {
|
||||||
|
@ -154,12 +154,12 @@ Message.prototype.decryptSessionKey = function(privateKey, password) {
|
||||||
if (!symESKeyPacketlist) {
|
if (!symESKeyPacketlist) {
|
||||||
throw new Error('No symmetrically encrypted session key packet found.');
|
throw new Error('No symmetrically encrypted session key packet found.');
|
||||||
}
|
}
|
||||||
await symESKeyPacketlist.map(async function(packet) {
|
await Promise.all(symESKeyPacketlist.map(async function(packet) {
|
||||||
try {
|
try {
|
||||||
await packet.decrypt(password);
|
await packet.decrypt(password);
|
||||||
keyPackets.push(packet);
|
keyPackets.push(packet);
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
});
|
}));
|
||||||
|
|
||||||
} else if (privateKey) {
|
} else if (privateKey) {
|
||||||
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.publicKeyEncryptedSessionKey);
|
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.publicKeyEncryptedSessionKey);
|
||||||
|
@ -170,21 +170,34 @@ Message.prototype.decryptSessionKey = function(privateKey, password) {
|
||||||
if (!privateKeyPacket.isDecrypted) {
|
if (!privateKeyPacket.isDecrypted) {
|
||||||
throw new Error('Private key is not decrypted.');
|
throw new Error('Private key is not decrypted.');
|
||||||
}
|
}
|
||||||
// TODO replace when Promise.some or Promise.any are implemented
|
await Promise.all(pkESKeyPacketlist.map(async function(packet) {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
await pkESKeyPacketlist.some(async function(packet) {
|
|
||||||
if (packet.publicKeyId.equals(privateKeyPacket.getKeyId())) {
|
if (packet.publicKeyId.equals(privateKeyPacket.getKeyId())) {
|
||||||
try {
|
try {
|
||||||
await packet.decrypt(privateKeyPacket);
|
await packet.decrypt(privateKeyPacket);
|
||||||
keyPackets.push(packet);
|
keyPackets.push(packet);
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
} else {
|
} else {
|
||||||
throw new Error('No key or password specified.');
|
throw new Error('No key or password specified.');
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
||||||
if (keyPackets.length) {
|
if (keyPackets.length) {
|
||||||
|
|
||||||
|
// Return only unique session keys
|
||||||
|
if (keyPackets.length > 1) {
|
||||||
|
var seen = {};
|
||||||
|
keyPackets = keyPackets.filter(function(item) {
|
||||||
|
var k = item.sessionKeyAlgorithm + util.Uint8Array2str(item.sessionKey);
|
||||||
|
if (seen.hasOwnProperty(k)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seen[k] = true;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return keyPackets.map(packet => ({ data: packet.sessionKey, algorithm: packet.sessionKeyAlgorithm }));
|
return keyPackets.map(packet => ({ data: packet.sessionKey, algorithm: packet.sessionKeyAlgorithm }));
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Session key decryption failed.');
|
throw new Error('Session key decryption failed.');
|
||||||
|
|
|
@ -414,18 +414,18 @@ export function encryptSessionKey({ data, algorithm, publicKeys, passwords }) {
|
||||||
* or 'undefined' if no key packets found
|
* or 'undefined' if no key packets found
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function decryptSessionKey({ message, privateKey, password }) {
|
export function decryptSessionKeys({ message, privateKey, password }) {
|
||||||
checkMessage(message);
|
checkMessage(message);
|
||||||
|
|
||||||
if (asyncProxy) { // use web worker if available
|
if (asyncProxy) { // use web worker if available
|
||||||
return asyncProxy.delegate('decryptSessionKey', { message, privateKey, password });
|
return asyncProxy.delegate('decryptSessionKeys', { message, privateKey, password });
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve().then(async function() {
|
return Promise.resolve().then(async function() {
|
||||||
|
|
||||||
return message.decryptSessionKey(privateKey, password);
|
return message.decryptSessionKeys(privateKey, password);
|
||||||
|
|
||||||
}).catch(onError.bind(null, 'Error decrypting session key'));
|
}).catch(onError.bind(null, 'Error decrypting session keys'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -525,7 +525,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('encryptSessionKey, decryptSessionKey', function() {
|
describe('encryptSessionKey, decryptSessionKeys', function() {
|
||||||
var sk = new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]);
|
var sk = new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]);
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
|
@ -539,7 +539,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
algorithm: 'aes128',
|
algorithm: 'aes128',
|
||||||
publicKeys: publicKey.keys
|
publicKeys: publicKey.keys
|
||||||
}).then(function(encrypted) {
|
}).then(function(encrypted) {
|
||||||
return openpgp.decryptSessionKey({
|
return openpgp.decryptSessionKeys({
|
||||||
message: encrypted.message,
|
message: encrypted.message,
|
||||||
privateKey: privateKey.keys[0]
|
privateKey: privateKey.keys[0]
|
||||||
});
|
});
|
||||||
|
@ -554,7 +554,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
algorithm: 'aes128',
|
algorithm: 'aes128',
|
||||||
passwords: password1
|
passwords: password1
|
||||||
}).then(function(encrypted) {
|
}).then(function(encrypted) {
|
||||||
return openpgp.decryptSessionKey({
|
return openpgp.decryptSessionKeys({
|
||||||
message: encrypted.message,
|
message: encrypted.message,
|
||||||
password: password1
|
password: password1
|
||||||
});
|
});
|
||||||
|
@ -563,14 +563,14 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('roundtrip workflow: encrypt, decryptSessionKey, decrypt with pgp key pair', function() {
|
it('roundtrip workflow: encrypt, decryptSessionKeys, decrypt with pgp key pair', function() {
|
||||||
var msgAsciiArmored;
|
var msgAsciiArmored;
|
||||||
return openpgp.encrypt({
|
return openpgp.encrypt({
|
||||||
data: plaintext,
|
data: plaintext,
|
||||||
publicKeys: publicKey.keys
|
publicKeys: publicKey.keys
|
||||||
}).then(function(encrypted) {
|
}).then(function(encrypted) {
|
||||||
msgAsciiArmored = encrypted.data;
|
msgAsciiArmored = encrypted.data;
|
||||||
return openpgp.decryptSessionKey({
|
return openpgp.decryptSessionKeys({
|
||||||
message: openpgp.message.readArmored(msgAsciiArmored),
|
message: openpgp.message.readArmored(msgAsciiArmored),
|
||||||
privateKey: privateKey.keys[0]
|
privateKey: privateKey.keys[0]
|
||||||
});
|
});
|
||||||
|
@ -586,14 +586,14 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('roundtrip workflow: encrypt, decryptSessionKey, decrypt with password', function() {
|
it('roundtrip workflow: encrypt, decryptSessionKeys, decrypt with password', function() {
|
||||||
var msgAsciiArmored;
|
var msgAsciiArmored;
|
||||||
return openpgp.encrypt({
|
return openpgp.encrypt({
|
||||||
data: plaintext,
|
data: plaintext,
|
||||||
passwords: password1
|
passwords: password1
|
||||||
}).then(function(encrypted) {
|
}).then(function(encrypted) {
|
||||||
msgAsciiArmored = encrypted.data;
|
msgAsciiArmored = encrypted.data;
|
||||||
return openpgp.decryptSessionKey({
|
return openpgp.decryptSessionKeys({
|
||||||
message: openpgp.message.readArmored(msgAsciiArmored),
|
message: openpgp.message.readArmored(msgAsciiArmored),
|
||||||
password: password1
|
password: password1
|
||||||
});
|
});
|
||||||
|
@ -608,6 +608,20 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
expect(decrypted.data).to.equal(plaintext);
|
expect(decrypted.data).to.equal(plaintext);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('roundtrip workflow: encrypt twice with one password, decryptSessionKeys, only one session key', function() {
|
||||||
|
return openpgp.encrypt({
|
||||||
|
data: plaintext,
|
||||||
|
passwords: [password1, password1]
|
||||||
|
}).then(function(encrypted) {
|
||||||
|
return openpgp.decryptSessionKeys({
|
||||||
|
message: openpgp.message.readArmored(encrypted.data),
|
||||||
|
password: password1
|
||||||
|
});
|
||||||
|
}).then(function(decryptedSessionKeys) {
|
||||||
|
expect(decryptedSessionKeys.length).to.equal(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('AES / RSA encrypt, decrypt, sign, verify', function() {
|
describe('AES / RSA encrypt, decrypt, sign, verify', function() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user