/// <summary>
        /// Create a signature from the input file and secret key provided.
        /// </summary>
        /// <param name="fileName">
        /// The filename of the target for which to generate the signature
        /// for.
        /// </param>
        /// <param name="keyIn">
        /// The secret keyfile input stream.
        /// </param>
        /// <param name="signatureStream">
        /// The file to which the signature shall be written to.
        /// </param>
        /// <param name="pass">
        /// The password for the secret key.
        /// </param>
        /// <param name="armor">
        /// Should the signature be generated as ASCII armor?
        /// </param>
        /// <returns>
        /// The <see cref="PgpSignature"/>.
        /// </returns>
        public static PgpSignature CreateDetachedFileSignature(
            string fileName,
            Stream keyIn,
            Stream signatureStream,
            char[] pass,
            bool armor)
        {
            if (armor)
            {
                signatureStream = new ArmoredOutputStream(signatureStream);
            }

            var secretKey          = PgpKeyHelper.ReadSecretKey(keyIn);
            var privateKey         = secretKey.ExtractPrivateKey(pass);
            var signatureGenerator = new PgpSignatureGenerator(secretKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);

            signatureGenerator.InitSign(PgpSignature.BinaryDocument, privateKey);

            var packetOutputStream = new BcpgOutputStream(signatureStream);

            using (var fileInputStream = File.OpenRead(fileName))
            {
                int read;
                var buffer = new byte[PgpCommon.BufferSize];
                while ((read = fileInputStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    signatureGenerator.Update(buffer, 0, read);
                }
            }

            var signature = signatureGenerator.Generate();

            signature.Encode(packetOutputStream);

            if (armor)
            {
                signatureStream.Dispose();
            }

            return(signature);
        }
        /// <summary>
        /// Decrypt file and verify file signature from stream.
        /// </summary>
        /// <param name="inputStream">
        /// The encrypted data input stream.
        /// </param>
        /// <param name="outputStream">
        /// The output stream.
        /// </param>
        /// <param name="privateKeyStream">
        /// The private key stream.
        /// </param>
        /// <param name="publicKeyStream">
        /// The public key stream.
        /// </param>
        /// <param name="passPhrase">
        /// The pass phrase.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/> value indicating whether or not the signature in
        /// the decrypted data is valid.
        /// </returns>
        public static bool DecryptAndVerifyStream(
            Stream inputStream,
            Stream outputStream,
            Stream privateKeyStream,
            Stream publicKeyStream,
            char[] passPhrase)
        {
            PgpPrivateKey             privateKey    = null;
            PgpPublicKeyEncryptedData encryptedData = null;
            var secretKeyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream));

            var encryptedDataList = GetEncryptedDataListFromStream(inputStream);

            foreach (PgpPublicKeyEncryptedData dataObject in encryptedDataList.GetEncryptedDataObjects())
            {
                privateKey = PgpKeyHelper.FindSecretKey(secretKeyRing, dataObject.KeyId, passPhrase);
                if (privateKey == null)
                {
                    continue;
                }

                encryptedData = dataObject;
                break;
            }

            if (privateKey == null)
            {
                throw new Exception("Unable to find secret key to decrypt the message");
            }

            var valid = ProcessDecryptionMessageBlocks(encryptedData, outputStream, publicKeyStream, privateKey);

            if (encryptedData.IsIntegrityProtected() && !encryptedData.Verify())
            {
                throw new PgpException("Data is integrity protected but integrity is lost.");
            }

            return(valid);
        }
        /// <summary>
        /// Decrypt a stream using the private key stream.
        /// </summary>
        /// <param name="inputStream">
        /// The stream of the encrypted file.
        /// </param>
        /// <param name="privateKeyStream">
        /// The stream of the private key file.
        /// </param>
        /// <param name="passPhrase">
        /// The pass phrase protecting the secret key.
        /// </param>
        /// <param name="outputFile">
        /// The file path to write the decrypted output to.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/> flag indicating decryption success; false states
        /// decryption failed because of a data integrity check error.
        /// </returns>
        public static bool DecryptFileStream(
            Stream inputStream,
            Stream privateKeyStream,
            string passPhrase,
            string outputFile)
        {
            PgpPrivateKey privateKey = null;
            var           valid      = true;

            try
            {
                PgpEncryptedDataList      encryptedDataList;
                PgpPublicKeyEncryptedData encryptedData = null;

                var objectFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream));
                var secretKeyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream));

                var @object = objectFactory.NextPgpObject();
                if (@object is PgpEncryptedDataList)
                {
                    encryptedDataList = (PgpEncryptedDataList)@object;
                }
                else
                {
                    encryptedDataList = (PgpEncryptedDataList)objectFactory.NextPgpObject();
                }

                foreach (PgpPublicKeyEncryptedData pked in encryptedDataList.GetEncryptedDataObjects())
                {
                    privateKey = PgpKeyHelper.FindSecretKey(secretKeyRing, pked.KeyId, passPhrase.ToCharArray());

                    if (privateKey == null)
                    {
                        continue;
                    }

                    encryptedData = pked;
                    break;
                }

                if (privateKey == null)
                {
                    throw new ArgumentException("Secret key for message not found.");
                }

                PgpObjectFactory plainFact;
                using (var clear = encryptedData.GetDataStream(privateKey))
                {
                    plainFact = new PgpObjectFactory(clear);
                }

                var message = plainFact.NextPgpObject();
                if (message is PgpCompressedData)
                {
                    var data = (PgpCompressedData)message;
                    PgpObjectFactory of;

                    using (var compDataIn = data.GetDataStream())
                    {
                        of = new PgpObjectFactory(compDataIn);
                    }

                    message = of.NextPgpObject();
                    if (message is PgpOnePassSignatureList)
                    {
                        message = of.NextPgpObject();
                        var literalData = (PgpLiteralData)message;
                        using (Stream output = File.Create(outputFile))
                        {
                            var unc = literalData.GetInputStream();
                            Streams.PipeAll(unc, output);
                        }
                    }
                    else
                    {
                        var literalData = (PgpLiteralData)message;
                        using (Stream output = File.Create(outputFile))
                        {
                            Stream unc = literalData.GetInputStream();
                            Streams.PipeAll(unc, output);
                        }
                    }
                }
                else if (message is PgpLiteralData)
                {
                    PgpLiteralData literalData = (PgpLiteralData)message;
                    string         unused      = literalData.FileName;

                    using (Stream outputStream = File.Create(outputFile))
                    {
                        Stream unc = literalData.GetInputStream();
                        Streams.PipeAll(unc, outputStream);
                    }
                }
                else if (message is PgpOnePassSignatureList)
                {
                    throw new PgpException("Encrypted message contains a signed message - not literal data.");
                }
                else
                {
                    throw new PgpException("Message is not a simple encrypted file - type unknown.");
                }

                if (encryptedData.IsIntegrityProtected())
                {
                    if (!encryptedData.Verify())
                    {
                        Console.Error.WriteLine("Message failed integrity check");
                        valid = false;
                    }
                    else
                    {
                        Console.Error.WriteLine("Message integrity check passed");
                    }
                }
            }
            catch (PgpException exception)
            {
                PgpCommon.DumpException(exception);
                throw;
            }

            return(valid);
        }
        /// <summary>
        /// Encrypt a file as specified by the input file path.
        /// </summary>
        /// <param name="inputFile">
        /// The file to encrypt.
        /// </param>
        /// <param name="outputFile">
        /// The file to write the encrypted content to.
        /// </param>
        /// <param name="publicKeyFile">
        /// The path to the public key file to use for encryption.
        /// </param>
        /// <param name="symmetricKeyAlgorithm">
        /// Encryption algorithm.
        /// </param>
        /// <param name="armor">
        /// Should the encrypted file be written using ASCII armor?
        /// </param>
        /// <param name="withIntegrityCheck">
        /// Should the integrity be verified?
        /// </param>
        /// <param name="compressionAlgorithm">
        /// Compression algorithm to use.
        /// </param>
        public static void EncryptFile(
            string inputFile,
            string outputFile,
            string publicKeyFile,
            SymmetricKeyAlgorithmTag symmetricKeyAlgorithm = SymmetricKeyAlgorithmTag.Aes256,
            bool armor = true,
            bool withIntegrityCheck = true,
            CompressionAlgorithmTag compressionAlgorithm = CompressionAlgorithmTag.Zip)
        {
            try
            {
                using (Stream publicKeyStream = File.OpenRead(publicKeyFile))
                {
                    PgpPublicKey encKey = PgpKeyHelper.ReadPublicKey(publicKeyStream);

                    using (var memoryStream = new MemoryStream())
                    {
                        var compressedDataGenerator = new PgpCompressedDataGenerator(compressionAlgorithm);
                        WriteFileToLiteralData(
                            compressedDataGenerator.Open(memoryStream),
                            PgpLiteralData.Binary,
                            new FileInfo(inputFile));

                        compressedDataGenerator.Close();
                        var encryptedDataGenerator = new PgpEncryptedDataGenerator(
                            symmetricKeyAlgorithm,
                            withIntegrityCheck,
                            new SecureRandom());

                        encryptedDataGenerator.AddMethod(encKey);
                        var bytes = memoryStream.ToArray();

                        using (Stream outputStream = File.Create(outputFile))
                        {
                            if (armor)
                            {
                                using (var armoredStream = new ArmoredOutputStream(outputStream))
                                    using (var encryptedStream = encryptedDataGenerator.Open(armoredStream, bytes.Length))
                                    {
                                        encryptedStream.Write(bytes, 0, bytes.Length);
                                    }
                            }
                            else
                            {
                                using (
                                    Stream encryptedOutputStream = encryptedDataGenerator.Open(
                                        outputStream,
                                        bytes.Length))
                                {
                                    encryptedOutputStream.Write(bytes, 0, bytes.Length);
                                }
                            }
                        }
                    }
                }
            }
            catch (PgpException exception)
            {
                PgpCommon.DumpException(exception);
                throw;
            }
        }