java - 使用 BouncyCaSTLe 解密 PGP/MIME 消息

标签 java encryption bouncycastle

我开始寻找一个可以帮助我使用 OpenPGP 加密/解密 MIME 消息的 JAVA 库,并找到了 BouncyCaSTLe。在尝试了解该库的工作原理时,我成功解密了 PGP/Inline 类型的 OpenPGP 加密 MIME 消息。 现在我尝试找出是否也可以使用 PGP/MIME 类型的 BouncyCaSTLe MIME 消息进行解密。 我在网上搜索了很多,但找不到任何提示是否可能,如果可能的话该怎么做。所以我决定把问题放在这里。 任何人都可以提供有关此主题的提示吗?

提前谢谢您!

最佳答案

使用文件中的 key (通常是 .asc 文件)或流中的 key 进行解密(具体取决于您的公司管理 key 的方式,使用 Bouncy CaSTLe:

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.");

            }
        }
    }
}

关于java - 使用 BouncyCaSTLe 解密 PGP/MIME 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31404248/

相关文章:

ios - iOS 应用程序中用于登录系统的标准程序是什么?

java - 使用 Java 中的 Bouncy CaSTLe 自签名 X509 证书

JAVA:如何在具有密码保护的pem文件中保存私钥

模拟简单数据库表的java类

java - 高效的 JSP/Tomcat 持久存储?

java - exec-maven-plugin 给出类未找到异常

java - WebRTC 和加密?

java - 获取 RSA 密码的 block 大小

java - 尝试在 Java 中初始化 Bouncy CaSTLe 密码时, key 长度不是 128/192/256 位

java - Spring-Hibernate 集成 : Unable to persist