使用BouncyCastle解密PGP / MIME Mesage

时间:2015-07-14 10:37:34

标签: java encryption bouncycastle

我开始搜索JAVA lib,它帮助我使用OpenPGP加密/解密MIME消息并找到BouncyCastle。在尝试理解lib的工作原理时,我成功解密了PGP / Inline类型的OpenPGP加密MIME消息。 现在我试着找出我是否也可以使用PGP / MIME类型的BouncyCastle MIME消息进行解密。 我在网上搜索了很多,如果可能的话,找不到任何提示,如果是的话,怎么办呢。所以我决定在这里提出这个问题。 任何人都可以暗示这个话题吗?

提前谢谢!

1 个答案:

答案 0 :(得分:1)

使用Bouncy Castle中的密钥(通常是.asc文件)或Streams(取决于贵公司管理密钥的方式)解密:

using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Utilities.IO;
using System;
using System.IO;
using System.Linq;

namespace Cryptor.Agents
{
    /// <summary>
    /// Decrypts a specified PGP Encrypted File with the specified Keys and Password
    /// </summary>
    public class PgpDecryptionAgent
    {
        private readonly string _encryptedFilePath;
        private readonly string _outputDirectory;
        private readonly PgpEncryptionKeys _pgpKeys;

        /// <summary>
        /// Constructs the PgpDecryptionAgent with PGP Keys in File
        /// </summary>
        /// <param name="encryptedFilePath">The path to the encrypted file</param>
        /// <param name="outputDirectory">The directory to which the file will be decrypted</param>
        /// <param name="publicKeyPath">The path to the public key</param>
        /// <param name="privateKeyPath">The path to the private key</param>
        /// <param name="password">The password to access the Private key</param>
        public PgpDecryptionAgent(string encryptedFilePath, string outputDirectory, string publicKeyPath, string privateKeyPath, string password)
        {
            _encryptedFilePath = encryptedFilePath;
            _outputDirectory = outputDirectory;
            _pgpKeys = new PgpEncryptionKeys(publicKeyPath, privateKeyPath, password);
        }

        /// <summary>
        /// Constructs the PgpDecryptionAgent with PGP Keys in Stream
        /// </summary>
        /// <param name="encryptedFilePath">The path to the encrypted file</param>
        /// <param name="outputDirectory">The directory to which the file will be decrypted</param>
        /// <param name="publicKey">Stream of the Public key</param>
        /// <param name="privateKey">Stream of the Private key</param>
        /// <param name="password">The password to access the Private key</param>
        public PgpDecryptionAgent(string encryptedFilePath, string outputDirectory, Stream publicKey, Stream privateKey, string password)
        {
            _encryptedFilePath = encryptedFilePath;
            _outputDirectory = outputDirectory;
            _pgpKeys = new PgpEncryptionKeys(publicKey, privateKey, password);
        }

        /// <summary>
        /// Performs the Decryption operation
        /// </summary>
        public void DecryptPgpEncryptedFile()
        {
            FileStream encryptedFile = new FileStream(_encryptedFilePath, FileMode.Open, FileAccess.Read);
            DecryptFile(encryptedFile, _outputDirectory);
        }

        /// <summary>
        /// Performs the Decryption operation
        /// </summary>
        /// <param name="input">The encrypted file input</param>
        /// <param name="outputpath">The decrypted file output</param>
        private void DecryptFile(Stream input, string outputpath)
        {
            input = PgpUtilities.GetDecoderStream(input);
            try
            {
                PgpObjectFactory pgpObjF = new PgpObjectFactory(input);
                PgpEncryptedDataList enc;
                PgpObject obj = pgpObjF.NextPgpObject();
                var list = obj as PgpEncryptedDataList;
                if (list != null)
                {
                    enc = list;
                }
                else
                {
                    enc = (PgpEncryptedDataList) pgpObjF.NextPgpObject();
                }
                PgpPrivateKey privKey = _pgpKeys.PrivateKey;
                PgpPublicKeyEncryptedData pbe = enc.GetEncryptedDataObjects().Cast<PgpPublicKeyEncryptedData>().FirstOrDefault(pked => privKey != null);
                if (pbe != null)
                {
                    Stream clear = pbe.GetDataStream(privKey);
                    PgpObjectFactory plainFact = new PgpObjectFactory(clear);
                    PgpObject message = plainFact.NextPgpObject();
                    var pgpCompressedData = message as PgpCompressedData;
                    if (pgpCompressedData == null) return;
                    PgpCompressedData cData = pgpCompressedData;
                    Stream compDataIn = cData.GetDataStream();
                    PgpObjectFactory o = new PgpObjectFactory(compDataIn);
                    message = o.NextPgpObject();
                    PgpLiteralData literalData;
                    if (message is PgpOnePassSignatureList)
                    {
                        message = o.NextPgpObject();
                        literalData = (PgpLiteralData) message;
                        Stream output = File.Create(outputpath + "\\" + literalData.FileName);
                        Stream unc = literalData.GetInputStream();
                        Streams.PipeAll(unc, output);
                    }
                    else
                    {
                        literalData = (PgpLiteralData) message;
                        Stream output = File.Create(outputpath + "\\" + literalData.FileName);
                        Stream unc = literalData.GetInputStream();
                        Streams.PipeAll(unc, output);
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        /// <summary>
        /// The PGP Encryption Keys
        /// </summary>
        public class PgpEncryptionKeys
        {
            public PgpPublicKey PublicKey { get; private set; }
            public PgpPrivateKey PrivateKey { get; private set; }
            public PgpSecretKey SecretKey { get; private set; }

            /// <summary>
            /// Configure Decryption from Key Streams
            /// </summary>
            /// <param name="publicKey">Stream of the Public Key</param>
            /// <param name="privateKey">Stream of the Private Key</param>
            /// <param name="password">Password to access the Private Key</param>
            public PgpEncryptionKeys(Stream publicKey, Stream privateKey, string password)
            {
                PublicKey = ReadPublicKeyFromStream(publicKey);
                SecretKey = ReadSecretKeyFromStream(privateKey);
                PrivateKey = ReadPrivateKey(password);
            }

            /// <summary>
            /// Configure Decryption from Key Files
            /// </summary>
            /// <param name="publicKeyPath">String path to the Public Key file</param>
            /// <param name="privateKeyPath">String path to the Private key file</param>
            /// <param name="passPhrase">Password to access the Private Key</param>
            public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, string passPhrase)
            {
                if (!File.Exists(publicKeyPath))
                    throw new ArgumentException("Public key file not found", "publicKeyPath");

                if (!File.Exists(privateKeyPath))
                    throw new ArgumentException("Private key file not found", "privateKeyPath");

                if (String.IsNullOrEmpty(passPhrase))
                    throw new ArgumentException("passPhrase is null or empty.", "passPhrase");

                PublicKey = ReadPublicKeyFromFile(publicKeyPath);
                SecretKey = ReadSecretKeyFromFile(privateKeyPath);
                PrivateKey = ReadPrivateKey(passPhrase);

            }

            /// <summary>
            /// Gets the Secret Key from a File (generally a .asc file)
            /// </summary>
            /// <param name="privateKeyPath">The path to the Private Key file</param>
            private PgpSecretKey ReadSecretKeyFromFile(string privateKeyPath)
            {
                using (Stream keyIn = File.OpenRead(privateKeyPath))
                {
                    return ReadSecretKeyFromStream(keyIn);
                }
            }

            /// <summary>
            /// Gets the Secret Key from a Stream
            /// </summary>
            /// <param name="keyIn">The Stream of the PGP</param>
            private PgpSecretKey ReadSecretKeyFromStream(Stream keyIn)
            {
                 using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
                {
                    PgpSecretKeyRingBundle secretKeyRingBundle = new PgpSecretKeyRingBundle(inputStream);
                    PgpSecretKey foundKey = GetFirstSecretKey(secretKeyRingBundle);
                    if (foundKey != null)
                        return foundKey;
                }
                throw new ArgumentException("Can't find signing key in key ring.");
            }

            /// <summary>
            /// Obtains the first secret key from the bundle
            /// </summary>
            /// <param name="secretKeyRingBundle"></param>
            /// <returns></returns>
            private PgpSecretKey GetFirstSecretKey(PgpSecretKeyRingBundle secretKeyRingBundle)
            {
                foreach (PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings())
                {
                    PgpSecretKey key = kRing.GetSecretKeys().Cast<PgpSecretKey>().FirstOrDefault(k => k.IsSigningKey);

                    if (key != null)
                        return key;
                }
                return null;
            }

            /// <summary>
            /// Gets the Public Key from a file (generally a .asc file)
            /// </summary>
            /// <param name="publicKeyPath">The path to the Public Key file</param>
            private PgpPublicKey ReadPublicKeyFromFile(string publicKeyPath)
            {
                using (Stream keyIn = File.OpenRead(publicKeyPath))
                {
                    return ReadPublicKeyFromStream(keyIn);
                }
            }

            /// <summary>
            /// Gets the Public Key from a Stream
            /// </summary>
            /// <param name="keyIn">The Stream of the Public Key</param>
            private PgpPublicKey ReadPublicKeyFromStream(Stream keyIn)
            {
                using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
                {
                    PgpPublicKeyRingBundle publicKeyRingBundle = new PgpPublicKeyRingBundle(inputStream);
                    PgpPublicKey foundKey = GetFirstPublicKey(publicKeyRingBundle);
                    if (foundKey != null)
                        return foundKey;
                }
                throw new ArgumentException("No encryption key found in public key ring.");
            }

            /// <summary>
            /// Gets the first Public Key from the bundle
            /// </summary>
            /// <param name="publicKeyRingBundle"></param>
            /// <returns></returns>
            private PgpPublicKey GetFirstPublicKey(PgpPublicKeyRingBundle publicKeyRingBundle)
            {
                foreach (PgpPublicKeyRing kRing in publicKeyRingBundle.GetKeyRings())
                {
                    PgpPublicKey key = kRing.GetPublicKeys()
                        .Cast<PgpPublicKey>()
                        .Where(k => k.IsEncryptionKey)
                        .FirstOrDefault();

                    if (key != null)
                        return key;
                }
                return null;
            }

            /// <summary>
            /// Reads the Private Key with the provided password
            /// </summary>
            /// <param name="passPhrase">The password to access the Private Key</param>
            private PgpPrivateKey ReadPrivateKey(string passPhrase)
            {
                PgpPrivateKey privateKey = SecretKey.ExtractPrivateKey(passPhrase.ToCharArray());
                if (privateKey != null)
                    return privateKey;

                throw new ArgumentException("No private key found in secret key.");

            }
        }
    }
}