private static PgpObject checkforOnePassSignatureList(PgpObject message, PgpObjectFactory compressedFactory)
 {
     message = compressedFactory.NextPgpObject();
     if (message is PgpOnePassSignatureList)
     {
         message = compressedFactory.NextPgpObject();
     }
     return message;
 }
 private static PgpObject processCompressedMessage(PgpObject message)
 {
     PgpCompressedData compressedData = (PgpCompressedData)message;
     Stream compressedDataStream = compressedData.GetDataStream();
     PgpObjectFactory compressedFactory = new PgpObjectFactory(compressedDataStream);
     message = checkforOnePassSignatureList(message, compressedFactory);
     return message;
 }
        /// <summary>
        /// Recursive PGP Object handler.
        /// </summary>
        /// <param name="obj">Object to handle</param>
        /// <returns>Returns decrypted data if any</returns>
        byte[] DecryptHandlePgpObject(PgpObject obj)
        {
            byte[] ret = null;

            if (obj is PgpEncryptedDataList)
            {
                Context.IsEncrypted = true;
                var dataList = obj as PgpEncryptedDataList;

                // Set once we have matched a keyid.
                bool secretKeyMatched = false;

                foreach (PgpPublicKeyEncryptedData encryptedData in dataList.GetEncryptedDataObjects())
                {
                    try
                    {
                        // NOTE: When content is encrypted to multiple reciepents, only one of these blocks
                        //       will match a known KeyId.  If a match is never made, then there is a problem :)
                        Context.SecretKey = GetSecretKey(encryptedData.KeyId);
                        if (Context.SecretKey == null)
                            continue;

                        secretKeyMatched = true;

                        using (var cleartextIn = encryptedData.GetDataStream(Context.SecretKey.ExtractPrivateKey(Context.Password)))
                        {
                            var clearFactory = new PgpObjectFactory(cleartextIn);
                            var nextObj = clearFactory.NextPgpObject();

                            var r = DecryptHandlePgpObject(nextObj);
                            if (r != null)
                                ret = r;
                        }

                        if (!encryptedData.Verify())
                            throw new VerifyException("Verify of encrypted data failed!");
                    }
                    catch (PgpException ex)
                    {
                        if (!(ex.InnerException is EndOfStreamException))
                            throw ex;
                    }
                }

                if(!secretKeyMatched)
                    throw new SecretKeyNotFoundException("Error, unable to locate decryption key.");
            }
            else if (obj is PgpCompressedData)
            {
                Context.IsCompressed = true;
                var compressedData = obj as PgpCompressedData;
                using (var compressedIn = compressedData.GetDataStream())
                {
                    var factory = new PgpObjectFactory(compressedIn);

                    do
                    {
                        var nextObj = factory.NextPgpObject();

                        if (nextObj == null)
                            break;

                        var r = DecryptHandlePgpObject(nextObj);
                        if (r != null)
                            ret = r;
                    }
                    while (true);
                }
            }
            else if (obj is PgpOnePassSignatureList)
            {
                Context.IsSigned = true;
                var signatureList = obj as PgpOnePassSignatureList;

                if (signatureList.Count > 1)
                    throw new CryptoException("Error, more than one signature present!");

                Context.OnePassSignature = signatureList[0];
                var publicKey = GetPublicKey(Context.OnePassSignature.KeyId);
                if (publicKey == null)
                {
                    Context.OnePassSignature = null;
                }
                else
                    Context.OnePassSignature.InitVerify(publicKey);
            }
            else if (obj is PgpSignatureList)
            {
                var signatureList = obj as PgpSignatureList;

                if (signatureList.Count > 1)
                    throw new CryptoException("Error, more than one signature present!");

                Context.Signature = signatureList[0];

                if (Context.IsSigned && Context.OnePassSignature == null)
                {
                    // We don't have signature key for validation
                    Context.SignatureValidated = false;
                    Context.SignedBy = null;
                }
                else if (Context.OnePassSignature == null)
                    throw new CryptoException("Error, OnePassSignature was not found!");
                else
                {
                    if (Context.OnePassSignature.Verify(Context.Signature))
                    {
                        Context.SignatureValidated = true;
                        Context.SignedBy = GetPublicKey(Context.Signature.KeyId);
                    }
                }
            }
            else if (obj is PgpLiteralData)
            {
                var literalData = obj as PgpLiteralData;

                using (var dataOut = new MemoryStream())
                {
                    using (var dataIn = literalData.GetInputStream())
                        dataIn.CopyTo(dataOut);

                    dataOut.Position = 0;

                    ret = dataOut.ToArray();
                }

                if(Context.OnePassSignature != null)
                    Context.OnePassSignature.Update(ret, 0, ret.Length);
            }
            else if (obj is PgpMarker)
            {
                // Skip, These packets are used by PGP 5.x to signal to earlier
                // versions of PGP (eg. 2.6.x) that the message requires newer
                // software to be read and understood.
            }
            else
            {
                throw new CryptoException("Unknown Pgp Object: " + obj.ToString());
            }

            return ret;
        }
		private byte[] HandlePgpEncryptedDataList(PgpObject obj)
		{
			logger.Trace("DecryptHandlePgpObject: IsEncrypted");
			Context.IsEncrypted = true;
			var dataList = (PgpEncryptedDataList) obj;

			byte[] ret = null;

			PgpPublicKeyEncryptedData encryptedData = null;
			PgpSecretKey masterSecretKey = null;
			PgpSecretKey secretKey = null;
			char[] passphrase = null;

			var hiddenRecipientData =
				dataList.GetEncryptedDataObjects().Cast<PgpPublicKeyEncryptedData>().FirstOrDefault(key => key.KeyId == 0);
			var knownKeyData =
				dataList.GetEncryptedDataObjects().Cast<PgpPublicKeyEncryptedData>().FirstOrDefault(key => GetSecretKey(key.KeyId) != null);

			if (hiddenRecipientData == null && knownKeyData == null)
			{
				logger.Debug("DecryptHandlePgpObject: Decryption key not found");
				throw new SecretKeyNotFoundException("Error, unable to locate decryption key.");
			}

			if (knownKeyData != null)
			{
				masterSecretKey = GetMasterSecretKey(knownKeyData.KeyId);
				secretKey = GetSecretKey(knownKeyData.KeyId);

				if (masterSecretKey == null || secretKey == null)
					return null;

				passphrase = Context.PasswordCallback(masterSecretKey, secretKey);

				// Incorrect passphrase or cancel
				if (passphrase == null)
					return null;

				encryptedData = knownKeyData;

				try
				{
					Context.SecretKey = masterSecretKey;

					logger.Trace("DecryptHandlePgpObject: Found key: {0:X}", secretKey.KeyId);

					using (var cleartextIn = encryptedData.GetDataStream(
						secretKey.ExtractPrivateKey(passphrase)))
					{
						var clearFactory = new PgpObjectFactory(cleartextIn);

						while (ret == null)
						{
							var nextObj = clearFactory.NextPgpObject();
							if (nextObj == null)
								return null;

							var r = DecryptHandlePgpObject(nextObj);
							if (r != null)
								ret = r;
						}
					}

					// This can fail due to integrity protection missing.
					// Legacy systems to not have this protection
					// Should make an option to ignore.
					try
					{
						if (!encryptedData.Verify())
						{
							logger.Debug("DecryptHandlePgpObject: encryptedData.Verify failed");
							throw new VerifyException("Verify of encrypted data failed!");
						}
					}
					catch (PgpException exx)
					{
						logger.Debug("DecryptHandlePgpObject: " + exx.Message);

						// Legacy systems do not have this protection
						// Exposed as a flag to allow library consumer to 
						// decide on correct coarse of action
						if (exx.Message == "data not integrity protected.")
							Context.FailedIntegrityCheck = true;
						else
							throw;
					}
				}
				catch (PgpException ex)
				{
					if (!(ex.InnerException is EndOfStreamException))
						throw;
				}

				return ret;
			}

			// hidden recipient path

			encryptedData = hiddenRecipientData;
			var foundKey = false;

			// Try all secret keys until we find a match
			foreach (var key in EnumerateAllEncryptionSecretKeys())
			{
				masterSecretKey = GetMasterSecretKey(key.KeyId);
				secretKey = key;

				passphrase = Context.PasswordCallback(masterSecretKey, secretKey);

				// Incorrect passphrase or cancel
				if (passphrase == null)
					continue;

				try
				{
					using (var cleartextIn = encryptedData.GetDataStream(secretKey.ExtractPrivateKey(passphrase)))
					{
						var clearFactory = new PgpObjectFactory(cleartextIn);

						while (ret == null)
						{
							var nextObj = clearFactory.NextPgpObject();

							logger.Trace("DecryptHandlePgpObject: Found key: {0:X}", secretKey.KeyId);
							foundKey = true;

							if (nextObj == null)
								return null;

							var r = DecryptHandlePgpObject(nextObj);
							if (r != null)
								ret = r;
						}
					}

					// This can fail due to integrity protection missing.
					// Legacy systems to not have this protection
					// Should make an option to ignore.
					try
					{
						if (!encryptedData.Verify())
						{
							logger.Debug("DecryptHandlePgpObject: encryptedData.Verify failed");
							throw new VerifyException("Verify of encrypted data failed!");
						}
					}
					catch (PgpException exx)
					{
						logger.Debug("DecryptHandlePgpObject: " + exx.Message);

						// Legacy systems do not have this protection
						// Exposed as a flag to allow library consumer to 
						// decide on correct coarse of action
						if (exx.Message == "data not integrity protected.")
							Context.FailedIntegrityCheck = true;
						else
							throw;
					}

					return ret;
				}
				catch (DataLengthException)
				{
					// ignore, key didn't match out data length
				}
				catch (PgpException ex)
				{
					if (foundKey && !(ex.InnerException is EndOfStreamException))
						throw;
				}
			}

			logger.Debug("DecryptHandlePgpObject: Decryption key not found");
			throw new SecretKeyNotFoundException("Error, unable to locate decryption key.");
		}
		/// <summary>
		/// Recursive PGP Object handler.
		/// </summary>
		/// <param name="obj">Object to handle</param>
		/// <returns>Returns decrypted data if any</returns>
		byte[] DecryptHandlePgpObject(PgpObject obj)
		{
			logger.Trace("DecryptHandlePgpObject(" + obj.GetType().Name + ")");

			byte[] ret = null;

			if (obj is PgpEncryptedDataList)
			{
				ret = HandlePgpEncryptedDataList(obj);
			}
			else if (obj is PgpCompressedData)
			{
				Context.IsCompressed = true;
				var compressedData = obj as PgpCompressedData;
				using (var compressedIn = compressedData.GetDataStream())
				{
					var factory = new PgpObjectFactory(compressedIn);

					do
					{
						var nextObj = factory.NextPgpObject();
						if (nextObj == null)
							break;

						var r = DecryptHandlePgpObject(nextObj);
						if (r != null)
							ret = r;
					}
					while (true);
				}
			}
			else if (obj is PgpOnePassSignatureList)
			{
				logger.Trace("DecryptHandlePgpObject: IsSigned");

				Context.IsSigned = true;
				var signatureList = obj as PgpOnePassSignatureList;

				if (signatureList.Count > 1)
				{
					logger.Error("DecryptHandlePgpObject: Error, more than one signature present!");
					throw new CryptoException("Error, more than one signature present!");
				}

				Context.OnePassSignature = signatureList[0];
				var publicKey = GetPublicKey(Context.OnePassSignature.KeyId);
				if (publicKey == null)
				{
					logger.Debug("DecryptHandlePgpObject: Failed to find public key: " + Context.OnePassSignature.KeyId);
					Context.OnePassSignature = null;
				}
				else
					Context.OnePassSignature.InitVerify(publicKey);
			}
			else if (obj is PgpSignatureList)
			{
				var signatureList = obj as PgpSignatureList;

				if (signatureList.Count > 1)
				{
					logger.Error("DecryptHandlePgpObject: Error, more than one signature present!");
					throw new CryptoException("Error, more than one signature present!");
				}

				Context.Signature = signatureList[0];
				Context.IsSigned = true;

				if (Context.IsSigned && Context.OnePassSignature == null)
				{
					logger.Warn("DecryptHandlePgpObject: We don't have signature key for validation");

					// We don't have signature key for validation
					Context.SignatureValidated = false;
					Context.SignedBy = null;
				}
				else if (Context.OnePassSignature == null)
				{
				}
				else
				{
					if (Context.OnePassSignature.Verify(Context.Signature))
					{
						logger.Trace("DecryptHandlePgpObject: Context.OnePassSignature.Verify passed");
						Context.SignatureValidated = true;
						Context.SignedBy = GetMasterPublicKey(Context.Signature.KeyId);
					}
					else
					{
						logger.Trace("DecryptHandlePgpObject: Context.OnePassSignature.Verify failed");
					}
				}
			}
			else if (obj is PgpLiteralData)
			{
				var literalData = obj as PgpLiteralData;

				using (var dataOut = new MemoryStream())
				{
					using (var dataIn = literalData.GetInputStream())
						dataIn.CopyTo(dataOut);

					dataOut.Position = 0;

					ret = dataOut.ToArray();
				}

				if (Context.OnePassSignature != null)
					Context.OnePassSignature.Update(ret, 0, ret.Length);
				else if (Context.Signature != null)
				{
					var publicKey = GetPublicKey(Context.Signature.KeyId);
					if (publicKey == null)
					{
						logger.Debug("DecryptHandlePgpObject: Failed to find public key: " + Context.OnePassSignature.KeyId);
						Context.Signature = null;
					}
					else
					{
						Context.Signature.InitVerify(publicKey);
						Context.Signature.Update(ret, 0, ret.Length);

						if (Context.Signature.Verify())
						{
							logger.Trace("DecryptHandlePgpObject: Context.Signature.Verify passed");
							Context.SignatureValidated = true;
							Context.SignedBy = GetMasterPublicKey(Context.Signature.KeyId);
						}
						else
						{
							logger.Trace("DecryptHandlePgpObject: Context.Signature.Verify failed");
						}
					}
				}
			}
			else if (obj is PgpMarker)
			{
				// Skip, These packets are used by PGP 5.x to signal to earlier 
				// versions of PGP (eg. 2.6.x) that the message requires newer 
				// software to be read and understood.
			}
			else
			{
				logger.Debug("DecryptHandlePgpObject: Unknown pgp object: " + obj.GetType().ToString());
				throw new CryptoException("Unknown Pgp Object: " + obj.GetType().ToString());
			}

			logger.Trace("DecryptHandlePgpObject: Returning " +
				(ret == null ? "null" : ret.Length.ToString()) + " bytes");

			return ret;
		}
		/// <summary>
		/// Recursive PGP Object handler.
		/// </summary>
		/// <param name="obj">Object to handle</param>
		/// <returns>Returns decrypted data if any</returns>
		byte[] DecryptHandlePgpObject(PgpObject obj)
		{
			logger.Trace("DecryptHandlePgpObject(" + obj.GetType().Name + ")");

			byte[] ret = null;

			if (obj is PgpEncryptedDataList)
			{
				logger.Trace("DecryptHandlePgpObject: IsEncrypted");
				Context.IsEncrypted = true;
				var dataList = obj as PgpEncryptedDataList;

				// Set once we have matched a keyid.
				bool secretKeyMatched = false;

				foreach (PgpPublicKeyEncryptedData encryptedData in dataList.GetEncryptedDataObjects())
				{
					try
					{
						// If we have already found a key to use, skip others. It is possible
						// to have all the keys in our ring.
						if (Context.SecretKey != null)
							continue;

						// NOTE: When content is encrypted to multiple recipients, only one of these blocks
						//       will match a known KeyId.  If a match is never made, then there is a problem :)

						var masterSecretKey = GetMasterSecretKey(encryptedData.KeyId);
						var secretKey = GetSecretKey(encryptedData.KeyId);

						if (masterSecretKey == null || secretKey == null)
							continue;

						var passphrase = Context.PasswordCallback(masterSecretKey, secretKey);

						// Incorrect passphrase or cancel
						if (passphrase == null)
							continue;

						Context.SecretKey = masterSecretKey;

						logger.Trace("DecryptHandlePgpObject: Found key: " + encryptedData.KeyId);
						secretKeyMatched = true;

						using (var cleartextIn = encryptedData.GetDataStream(
							secretKey.ExtractPrivateKey(passphrase)))
						{
							var clearFactory = new PgpObjectFactory(cleartextIn);
							var nextObj = clearFactory.NextPgpObject();
							if (nextObj == null)
								return null;

							var r = DecryptHandlePgpObject(nextObj);
							if (r != null)
								ret = r;
						}

						// This can fail due to integrity protection missing.
						// Legacy systems to not have this protection
						// Should make an option to ignore.
						try
						{
							if (!encryptedData.Verify())
							{
								logger.Debug("DecryptHandlePgpObject: encryptedData.Verify failed");
								throw new VerifyException("Verify of encrypted data failed!");
							}
						}
						catch (PgpException exx)
						{
							logger.Debug("DecryptHandlePgpObject: " + exx.Message);

							// Legacy systems do not have this protection
							// Exposed as a flag to allow library consumer to 
							// decide on correct coarse of action
							if (exx.Message == "data not integrity protected.")
								Context.FailedIntegrityCheck = true;
							else
								throw;
						}
					}
					catch (PgpException ex)
					{
						if (!(ex.InnerException is EndOfStreamException))
							throw ex;
					}
				}

				if (!secretKeyMatched)
				{
					logger.Debug("DecryptHandlePgpObject: Decryption key not found");
					throw new SecretKeyNotFoundException("Error, unable to locate decryption key.");
				}
			}
			else if (obj is PgpCompressedData)
			{
				Context.IsCompressed = true;
				var compressedData = obj as PgpCompressedData;
				using (var compressedIn = compressedData.GetDataStream())
				{
					var factory = new PgpObjectFactory(compressedIn);

					do
					{
						var nextObj = factory.NextPgpObject();
						if (nextObj == null)
							break;

						var r = DecryptHandlePgpObject(nextObj);
						if (r != null)
							ret = r;
					}
					while (true);
				}
			}
			else if (obj is PgpOnePassSignatureList)
			{
				logger.Trace("DecryptHandlePgpObject: IsSigned");

				Context.IsSigned = true;
				var signatureList = obj as PgpOnePassSignatureList;

				if (signatureList.Count > 1)
				{
					logger.Error("DecryptHandlePgpObject: Error, more than one signature present!");
					throw new CryptoException("Error, more than one signature present!");
				}

				Context.OnePassSignature = signatureList[0];
				var publicKey = GetPublicKey(Context.OnePassSignature.KeyId);
				if (publicKey == null)
				{
					logger.Debug("DecryptHandlePgpObject: Failed to find public key: " + Context.OnePassSignature.KeyId);
					Context.OnePassSignature = null;
				}
				else
					Context.OnePassSignature.InitVerify(publicKey);
			}
			else if (obj is PgpSignatureList)
			{
				var signatureList = obj as PgpSignatureList;

				if (signatureList.Count > 1)
				{
					logger.Error("DecryptHandlePgpObject: Error, more than one signature present!");
					throw new CryptoException("Error, more than one signature present!");
				}

				Context.Signature = signatureList[0];
				Context.IsSigned = true;

				if (Context.IsSigned && Context.OnePassSignature == null)
				{
					logger.Warn("DecryptHandlePgpObject: We don't have signature key for validation");

					// We don't have signature key for validation
					Context.SignatureValidated = false;
					Context.SignedBy = null;
				}
				else if (Context.OnePassSignature == null)
				{
				}
				else
				{
					if (Context.OnePassSignature.Verify(Context.Signature))
					{
						logger.Trace("DecryptHandlePgpObject: Context.OnePassSignature.Verify passed");
						Context.SignatureValidated = true;
						Context.SignedBy = GetMasterPublicKey(Context.Signature.KeyId);
					}
					else
					{
						logger.Trace("DecryptHandlePgpObject: Context.OnePassSignature.Verify failed");
					}
				}
			}
			else if (obj is PgpLiteralData)
			{
				var literalData = obj as PgpLiteralData;

				using (var dataOut = new MemoryStream())
				{
					using (var dataIn = literalData.GetInputStream())
						dataIn.CopyTo(dataOut);

					dataOut.Position = 0;

					ret = dataOut.ToArray();
				}

				if (Context.OnePassSignature != null)
					Context.OnePassSignature.Update(ret, 0, ret.Length);
				else if (Context.Signature != null)
				{
					var publicKey = GetPublicKey(Context.Signature.KeyId);
					if (publicKey == null)
					{
						logger.Debug("DecryptHandlePgpObject: Failed to find public key: " + Context.OnePassSignature.KeyId);
						Context.Signature = null;
					}
					else
					{
						Context.Signature.InitVerify(publicKey);
						Context.Signature.Update(ret, 0, ret.Length);

						if (Context.Signature.Verify())
						{
							logger.Trace("DecryptHandlePgpObject: Context.Signature.Verify passed");
							Context.SignatureValidated = true;
							Context.SignedBy = GetMasterPublicKey(Context.Signature.KeyId);
						}
						else
						{
							logger.Trace("DecryptHandlePgpObject: Context.Signature.Verify failed");
						}
					}
				}
			}
			else if (obj is PgpMarker)
			{
				// Skip, These packets are used by PGP 5.x to signal to earlier 
				// versions of PGP (eg. 2.6.x) that the message requires newer 
				// software to be read and understood.
			}
			else
			{
				logger.Debug("DecryptHandlePgpObject: Unknown pgp object: " + obj.GetType().ToString());
				throw new CryptoException("Unknown Pgp Object: " + obj.GetType().ToString());
			}

			logger.Trace("DecryptHandlePgpObject: Returning " +
				(ret == null ? "null" : ret.Length.ToString()) + " bytes");

			return ret;
		}