/// <summary>
        /// Verify encryption parameters.
        /// </summary>
        /// <param name="inputFile">
        /// The input file.
        /// </param>
        /// <param name="publicKeyFile">
        /// The public key file.
        /// </param>
        /// <param name="privateKeyFile">
        /// The private key file.
        /// </param>
        /// <param name="passPhrase">
        /// The pass phrase.
        /// </param>
        /// <param name="encryptionKeys">
        /// The encryption keys.
        /// </param>
        /// <exception cref="FileNotFoundException">
        /// Thrown if any of the paths specified are invalid.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// Thrown if the encryption keys or passphrase are null.
        /// </exception>
        private static void VerifyEncryptionParameters(
            string inputFile,
            string publicKeyFile,
            string privateKeyFile,
            string passPhrase,
            PgpKeyContainer encryptionKeys)
        {
            if (!File.Exists(inputFile))
            {
                throw new FileNotFoundException(string.Format("Input file [{0}] does not exist.", inputFile));
            }

            if (!File.Exists(publicKeyFile))
            {
                throw new FileNotFoundException(string.Format("Public Key file [{0}] does not exist.", publicKeyFile));
            }

            if (!File.Exists(privateKeyFile))
            {
                throw new FileNotFoundException(string.Format("Private Key file [{0}] does not exist.", privateKeyFile));
            }

            if (string.IsNullOrEmpty(passPhrase))
            {
                throw new ArgumentNullException(nameof(passPhrase));
            }

            if (encryptionKeys == null)
            {
                throw new ArgumentNullException(nameof(encryptionKeys));
            }
        }
        /// <summary>
        /// Output encrypted data stream
        /// </summary>
        /// <param name="inputFile">
        /// The input file.
        /// </param>
        /// <param name="outputStream">
        /// The output stream.
        /// </param>
        /// <param name="encryptionKeys">
        /// The encryption keys.
        /// </param>
        /// <param name="integrityProtected">
        /// Integrity protect?
        /// </param>
        /// <param name="symmetricKeyAlgorithm">
        /// Symmetric algorithm.
        /// </param>
        /// <param name="compressionAlgorithm">
        /// Compression algorithm.
        /// </param>
        private static void OutputEncrypted(
            string inputFile,
            Stream outputStream,
            PgpKeyContainer encryptionKeys,
            bool integrityProtected,
            SymmetricKeyAlgorithmTag symmetricKeyAlgorithm = SymmetricKeyAlgorithmTag.Aes128,
            CompressionAlgorithmTag compressionAlgorithm   = CompressionAlgorithmTag.Zip)
        {
            using (
                var encryptedOut = ChainEncryptedOut(
                    outputStream,
                    encryptionKeys,
                    integrityProtected,
                    symmetricKeyAlgorithm))
                using (var compressedOut = ChainCompressedOut(encryptedOut, compressionAlgorithm))
                {
                    var unencryptedFileInfo = new FileInfo(inputFile);
                    var signatureGenerator  = InitSignatureGenerator(compressedOut, encryptionKeys);

                    using (var literalOut = ChainLiteralOut(compressedOut, unencryptedFileInfo))
                        using (var inputFileStream = unencryptedFileInfo.OpenRead())
                        {
                            WriteOutputAndSign(compressedOut, literalOut, inputFileStream, signatureGenerator);
                        }
                }
        }
        /// <summary>
        /// Chain the encrypted output.
        /// </summary>
        /// <param name="outputStream">
        /// The output stream.
        /// </param>
        /// <param name="encryptionKeys">
        /// The encryption keys.
        /// </param>
        /// <param name="integrityProtected">
        /// Integrity protect?
        /// </param>
        /// <param name="symmetricKeyAlgorithm">
        /// Symmetric algorithm.
        /// </param>
        /// <returns>
        /// The <see cref="Stream"/>.
        /// </returns>
        private static Stream ChainEncryptedOut(
            Stream outputStream,
            PgpKeyContainer encryptionKeys,
            bool integrityProtected,
            SymmetricKeyAlgorithmTag symmetricKeyAlgorithm = SymmetricKeyAlgorithmTag.Aes128)
        {
            var encryptedDataGenerator = new PgpEncryptedDataGenerator(
                symmetricKeyAlgorithm,
                integrityProtected,
                new SecureRandom());

            encryptedDataGenerator.AddMethod(encryptionKeys.PublicKey);
            return(encryptedDataGenerator.Open(outputStream, new byte[PgpCommon.BufferSize]));
        }
        /// <summary>
        /// Encrypt and sign the file.
        /// </summary>
        /// <param name="inputFile">
        /// Input path of the file to encrypt.
        /// </param>
        /// <param name="outputFile">
        /// Output path of the encrypted file.
        /// </param>
        /// <param name="publicKeyFile">
        /// Path to the public key file.
        /// </param>
        /// <param name="privateKeyFile">
        /// Path to the secret key file containing the private key.
        /// </param>
        /// <param name="passPhrase">
        /// The passphrase protecting the secret file.
        /// </param>
        /// <param name="symmetricKeyAlgorithm">
        /// Symmetric encryption algorithm.
        /// </param>
        /// <param name="armor">
        /// Should the encrypted file be written as ASCII armor?
        /// </param>
        /// <param name="integrityProtect">
        /// Integrity protect?
        /// </param>
        /// <param name="compressionAlgorithm">
        /// Compression algorithm to use.
        /// </param>
        /// <exception cref="FileNotFoundException">
        /// Throws a <see cref="FileNotFoundException"/> if the input, public
        /// key or secret key files do not exist.
        /// </exception>
        public static void EncryptAndSignFile(
            string inputFile,
            string outputFile,
            string publicKeyFile,
            string privateKeyFile,
            string passPhrase,
            SymmetricKeyAlgorithmTag symmetricKeyAlgorithm = SymmetricKeyAlgorithmTag.Aes256,
            bool armor            = true,
            bool integrityProtect = true,
            CompressionAlgorithmTag compressionAlgorithm = CompressionAlgorithmTag.Zip)
        {
            var encryptionKeys = new PgpKeyContainer(publicKeyFile, privateKeyFile, passPhrase);

            VerifyEncryptionParameters(inputFile, publicKeyFile, privateKeyFile, passPhrase, encryptionKeys);

            using (Stream outputStream = File.Create(outputFile))
            {
                if (armor)
                {
                    using (var armoredOutputStream = new ArmoredOutputStream(outputStream))
                    {
                        OutputEncrypted(
                            inputFile,
                            armoredOutputStream,
                            encryptionKeys,
                            integrityProtect,
                            symmetricKeyAlgorithm,
                            compressionAlgorithm);
                    }
                }
                else
                {
                    OutputEncrypted(
                        inputFile,
                        outputStream,
                        encryptionKeys,
                        integrityProtect,
                        symmetricKeyAlgorithm,
                        compressionAlgorithm);
                }
            }
        }
        /// <summary>
        /// Initialise the signature generator.
        /// </summary>
        /// <param name="compressedOutputStream">
        /// The compressed output.
        /// </param>
        /// <param name="encryptionKeys">
        /// The PGP encryption key container.
        /// </param>
        /// <returns>
        /// The <see cref="PgpSignatureGenerator"/>.
        /// </returns>
        private static PgpSignatureGenerator InitSignatureGenerator(
            Stream compressedOutputStream,
            PgpKeyContainer encryptionKeys)
        {
            const bool IsCritical = false;
            const bool IsNested   = false;

            var tag = encryptionKeys.SecretKey.PublicKey.Algorithm;
            var pgpSignatureGenerator = new PgpSignatureGenerator(tag, HashAlgorithmTag.Sha256);

            pgpSignatureGenerator.InitSign(PgpSignature.BinaryDocument, encryptionKeys.PrivateKey);

            foreach (string userId in encryptionKeys.SecretKey.PublicKey.GetUserIds())
            {
                var subPacketGenerator = new PgpSignatureSubpacketGenerator();
                subPacketGenerator.SetSignerUserId(IsCritical, userId);
                pgpSignatureGenerator.SetHashedSubpackets(subPacketGenerator.Generate());
                break;
            }

            pgpSignatureGenerator.GenerateOnePassVersion(IsNested).Encode(compressedOutputStream);
            return(pgpSignatureGenerator);
        }