diff --git a/src/message.js b/src/message.js
index 26a6ab04..539c1791 100644
--- a/src/message.js
+++ b/src/message.js
@@ -213,21 +213,31 @@ Message.prototype.getText = function() {
  * Encrypt the message either with public keys, passwords, or both at once.
  * @param  {Array<Key>} keys           (optional) public key(s) for message encryption
  * @param  {Array<String>} 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) {
-      symAlgo = keyModule.getPreferredSymAlgo(keys);
+      symAlgo = enums.read(enums.symmetric, keyModule.getPreferredSymAlgo(keys));
     } else if (passwords) {
-      symAlgo = config.encryption_cipher;
+      symAlgo = enums.read(enums.symmetric, config.encryption_cipher);
     } else {
       throw new Error('No keys or passwords');
     }
 
-    let sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, symAlgo));
-    msg = encryptSessionKey(sessionKey, enums.read(enums.symmetric, symAlgo), keys, passwords);
+    if (sessionKey) {
+      if (!util.isUint8Array(sessionKey.data) || !util.isString(sessionKey.algorithm)) {
+        throw new Error('Invalid session key for encryption.');
+      }
+      symAlgo = sessionKey.algorithm;
+      sessionKey = sessionKey.data;
+    } else {
+      sessionKey = crypto.generateSessionKey(symAlgo);
+    }
+
+    msg = encryptSessionKey(sessionKey, symAlgo, keys, passwords);
 
     if (config.aead_protect) {
       symEncryptedPacket = new packet.SymEncryptedAEADProtected();
@@ -238,12 +248,18 @@ Message.prototype.encrypt = function(keys, passwords) {
     }
     symEncryptedPacket.packets = this.packets;
 
-    return symEncryptedPacket.encrypt(enums.read(enums.symmetric, symAlgo), sessionKey);
+    return symEncryptedPacket.encrypt(symAlgo, sessionKey);
 
   }).then(() => {
     msg.packets.push(symEncryptedPacket);
     symEncryptedPacket.packets = new packet.List(); // remove packets after encryption
-    return msg;
+    return {
+      message: msg,
+      sessionKey: {
+        data: sessionKey,
+        algorithm: symAlgo
+      }
+    };
   });
 };
 
diff --git a/src/openpgp.js b/src/openpgp.js
index b01beef4..0129598e 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -177,20 +177,22 @@ export function decryptKey({ privateKey, passphrase }) {
  * @param  {Key|Array<Key>} publicKeys        (optional) array of keys or single key, used to encrypt the message
  * @param  {Key|Array<Key>} privateKeys       (optional) private keys for signing. If omitted message will not be signed
  * @param  {String|Array<String>} 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)
  * @param  {Signature} signature              (optional) a detached signature to add to the encrypted message
+ * @param  {Boolean} returnSessionKey         (optional) if the unencrypted session key should be added to returned object
  * @return {Promise<Object>}                  encrypted (and optionally signed message) in the form:
  *                                              {data: ASCII armored message if 'armor' is true,
  *                                                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, returnSessionKey=false}) {
   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, returnSessionKey });
   }
   var result = {};
   return Promise.resolve().then(() => {
@@ -211,13 +213,16 @@ 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 => {
+  }).then(encrypted => {
     if (armor) {
-      result.data = message.armor();
+      result.data = encrypted.message.armor();
     } else {
-      result.message = message;
+      result.message = encrypted.message;
+    }
+    if (returnSessionKey) {
+      result.sessionKey = encrypted.sessionKey;
     }
     return result;
   }).catch(onError.bind(null, 'Error encrypting message'));
diff --git a/test/general/key.js b/test/general/key.js
index 2de33d11..10a8dde3 100644
--- a/test/general/key.js
+++ b/test/general/key.js
@@ -931,7 +931,7 @@ describe('Key', function() {
       key = newKey;
       return openpgp.message.fromText('hello').encrypt([key.key]);
     }).then(function(msg) {
-      return msg.decrypt(key.key);
+      return msg.message.decrypt(key.key);
     }).catch(function(err) {
       expect(err.message).to.equal('Private key is not decrypted.');
     });
diff --git a/test/general/openpgp.js b/test/general/openpgp.js
index e3481b2d..0d31e93f 100644
--- a/test/general/openpgp.js
+++ b/test/general/openpgp.js
@@ -629,6 +629,71 @@ describe('OpenPGP.js public api tests', function() {
           });
         });
 
+        it('should encrypt then decrypt using returned session key', function() {
+          var encOpt = {
+            data: plaintext,
+            publicKeys: publicKey.keys,
+            returnSessionKey: true
+          };
+
+          return openpgp.encrypt(encOpt).then(function(encrypted) {
+            expect(encrypted.data).to.match(/^-----BEGIN PGP MESSAGE/);
+            var decOpt = {
+              sessionKey: encrypted.sessionKey,
+              message: openpgp.message.readArmored(encrypted.data)
+            };
+            return openpgp.decrypt(decOpt);
+          }).then(function(decrypted) {
+            expect(decrypted.data).to.equal(plaintext);
+            expect(decrypted.signatures).to.exist;
+            expect(decrypted.signatures.length).to.equal(0);
+          });
+        });
+
+        it('should encrypt using 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,