From 7e03410bc9c2ac81e0517db7e075bc24f0114620 Mon Sep 17 00:00:00 2001 From: Sanjana Rajan Date: Fri, 1 Dec 2017 21:25:43 -0800 Subject: [PATCH] allow sessionKey param in top level encrypt --- src/message.js | 14 +++++++++++-- src/openpgp.js | 7 ++++--- test/general/openpgp.js | 44 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/message.js b/src/message.js index 26a6ab04..c4fedd1b 100644 --- a/src/message.js +++ b/src/message.js @@ -213,9 +213,10 @@ Message.prototype.getText = function() { * Encrypt the message either with public keys, passwords, or both at once. * @param {Array} keys (optional) public key(s) for message encryption * @param {Array} passwords (optional) password(s) for message encryption + * @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String } * @return {Message} new message with encrypted content */ -Message.prototype.encrypt = function(keys, passwords) { +Message.prototype.encrypt = function(keys, passwords, sessionKey) { let symAlgo, msg, symEncryptedPacket; return Promise.resolve().then(() => { if (keys) { @@ -226,7 +227,16 @@ Message.prototype.encrypt = function(keys, passwords) { throw new Error('No keys or passwords'); } - let sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, symAlgo)); + if (sessionKey) { + if (!util.isUint8Array(sessionKey.data) || !util.isString(sessionKey.algorithm)) { + throw new Error('Invalid session key for encryption.'); + } + symAlgo = enums.write(enums.symmetric, sessionKey.algorithm); + sessionKey = sessionKey.data; + } else { + sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, symAlgo)); + } + msg = encryptSessionKey(sessionKey, enums.read(enums.symmetric, symAlgo), keys, passwords); if (config.aead_protect) { diff --git a/src/openpgp.js b/src/openpgp.js index b01beef4..f131161f 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -177,6 +177,7 @@ export function decryptKey({ privateKey, passphrase }) { * @param {Key|Array} publicKeys (optional) array of keys or single key, used to encrypt the message * @param {Key|Array} privateKeys (optional) private keys for signing. If omitted message will not be signed * @param {String|Array} passwords (optional) array of passwords or a single password to encrypt the message + * @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String } * @param {String} filename (optional) a filename for the literal data packet * @param {Boolean} armor (optional) if the return values should be ascii armored or the message/signature objects * @param {Boolean} detached (optional) if the signature should be detached (if true, signature will be added to returned object) @@ -186,11 +187,11 @@ export function decryptKey({ privateKey, passphrase }) { * message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true} * @static */ -export function encrypt({ data, publicKeys, privateKeys, passwords, filename, armor=true, detached=false, signature=null }) { +export function encrypt({ data, publicKeys, privateKeys, passwords, sessionKey, filename, armor=true, detached=false, signature=null }) { checkData(data); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported - return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, filename, armor, detached, signature }); + return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, sessionKey, filename, armor, detached, signature }); } var result = {}; return Promise.resolve().then(() => { @@ -211,7 +212,7 @@ export function encrypt({ data, publicKeys, privateKeys, passwords, filename, ar message = message.sign(privateKeys, signature); } } - return message.encrypt(publicKeys, passwords); + return message.encrypt(publicKeys, passwords, sessionKey); }).then(message => { if (armor) { diff --git a/test/general/openpgp.js b/test/general/openpgp.js index e3481b2d..d8acea17 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -629,6 +629,50 @@ describe('OpenPGP.js public api tests', function() { }); }); + it('should encrypt with custom session key and decrypt using session key', function() { + var sessionKey = { + data: openpgp.crypto.generateSessionKey('aes256'), + algorithm: 'aes256' + }; + var encOpt = { + data: plaintext, + sessionKey: sessionKey, + publicKeys: publicKey.keys + }; + var decOpt = { + sessionKey: sessionKey + }; + return openpgp.encrypt(encOpt).then(function(encrypted) { + expect(encrypted.data).to.match(/^-----BEGIN PGP MESSAGE/); + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { + expect(decrypted.data).to.equal(plaintext); + }); + }); + + it('should encrypt using custom session key and decrypt using private key', function() { + var sessionKey = { + data: openpgp.crypto.generateSessionKey('aes128'), + algorithm: 'aes128' + }; + var encOpt = { + data: plaintext, + sessionKey: sessionKey, + publicKeys: publicKey.keys + }; + var decOpt = { + privateKey: privateKey.keys[0] + }; + return openpgp.encrypt(encOpt).then(function(encrypted) { + expect(encrypted.data).to.match(/^-----BEGIN PGP MESSAGE/); + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { + expect(decrypted.data).to.equal(plaintext); + }); + }); + it('should encrypt/sign and decrypt/verify', function() { var encOpt = { data: plaintext,