【问题标题】:Decrypt PGP/MIME Mesage with BouncyCastle使用 BouncyCastle 解密 PGP/MIME 消息
【发布时间】:2016-04-22 23:31:25
【问题描述】:

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

提前谢谢你!

【问题讨论】:

    标签: java encryption bouncycastle


    【解决方案1】:

    使用文件(通常是 .asc 文件)或 Streams 中的密钥解密(取决于您的公司如何管理密钥,使用 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.");
    
                }
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      DidiSoft 的商业广告OpenPGP library for Java 是可能的:

          PGPMailUtils mailUtil = new PGPMailUtils();
          if (mailUtil.isOpenPGPEncrypted(message)) {
      
              try {
                  MimeMessage decrypted = 
                             mailUtil.decryptMessage(emailSession, 
                                                     (MimeMessage)message, 
                                                     "c:\\Projects\\PGPKeys\\private.key", 
                                                     "changeit");
      
                  Object decryptedRawContent = decrypted.getContent(); 
                  if (decryptedRawContent instanceof Multipart) {
                      Multipart multipart = (Multipart) decryptedRawContent;
      
                       for (int j = 0; j < multipart.getCount(); j++) {
                        BodyPart bodyPart = multipart.getBodyPart(j);
      
                        String disposition = bodyPart.getDisposition();
                        if (disposition != null && (disposition.equalsIgnoreCase("ATTACHMENT"))) { 
                            System.out.println("Mail have some attachment");
      
                            DataHandler handler = bodyPart.getDataHandler();
                            System.out.println("file name : " + handler.getName());                                 
                    // save here the file ...
                        } else { 
                    // print the decrypted text then
                            String content = getText(bodyPart);
                            System.out.println(content);
                        }   
                       }
                  } else {
                      // pgp inline mail, just print the decrypted text then
                      String content = message.getContent().toString();
                      System.out.println(content);
                  }               
              } catch (Exception e) {
                  System.out.println(e.getMessage());
              }
          } else if (mailUtil.isOpenPGPSigned(message)) {
              // pgp signed only message
              MimeBodyPart decrypted = mailUtil.getSignedContent(message);
              String content = getText(decrypted);
              System.out.println(content);
          } else {
              System.out.println(message.getContentType());
          }
      

      免责声明:我为滴滴软件工作。

      【讨论】:

      • 您的用户名表明您隶属于滴滴软件。也许你应该澄清这一点。
      • 感谢您的及时通知,我已经更新了答案。
      • @PeterKalef'DidiSoft 非常感谢您提供的信息以及您发布的代码。我也一定会看看这个图书馆。但是从您的回答中,我想到了一个问题。您是否在不使用 BouncyCastle 库的情况下实现了 PGP/MIME 的解密?或者您是否也将它用于 PGP/MIME 但提供更多应用程序级别的 API?感谢您的回复。
      • @Uzay,我们提供高级 API 并依赖于低级 BouncyCastle OpenPGP 功能。
      • @PeterKalef'DidiSoft 非常感谢您的澄清!
      猜你喜欢
      • 2013-10-10
      • 2011-10-22
      • 2011-08-05
      • 2019-07-14
      • 1970-01-01
      • 2015-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多