【问题标题】:C# How to simply encrypt a text file with a PGP Public Key?C# 如何使用 PGP 公钥简单地加密文本文件?
【发布时间】:2011-05-10 16:31:57
【问题描述】:

我对如何实现我在问题中所说的进行了一些研究,发现了几个 API,但其中大多数看起来非常复杂,因为我只是这个领域的菜鸟,我只想要一个简单的方法,比如:

public String Encrypt(String message, PublicKey publicKey)

不知道能不能做到?如果不是那么请有人启发我另一种方法来实现这一点:)

谢谢。

更新:

到目前为止,我只看到所有用于 OpenPGP 加密的库都需要公钥和私钥来进行加密,而我只想用公钥加密(因为我没有私钥使用它)!

【问题讨论】:

    标签: c# encryption public-key pgp public-key-encryption


    【解决方案1】:

    我找到了一个教程here,但它需要密钥和公钥来加密数据。但是,我对代码进行了一些修改,只需要公钥(不签名,不压缩),并认为我应该在这里发布它,以防有人也在寻找这个问题的解决方案。以下是修改后的代码,所有的功劳归于作者-Mr. Kim。

    public class PgpEncrypt
        {
            private PgpEncryptionKeys m_encryptionKeys;
            private const int BufferSize = 0x10000; 
            /// <summary>
            /// Instantiate a new PgpEncrypt class with initialized PgpEncryptionKeys.
            /// </summary>
            /// <param name="encryptionKeys"></param>
            /// <exception cref="ArgumentNullException">encryptionKeys is null</exception>
            public PgpEncrypt(PgpEncryptionKeys encryptionKeys)
            {
                if (encryptionKeys == null)
                {
                    throw new ArgumentNullException("encryptionKeys", "encryptionKeys is null.");
                }
                m_encryptionKeys = encryptionKeys;
            }
            /// <summary>
            /// Encrypt and sign the file pointed to by unencryptedFileInfo and
            /// write the encrypted content to outputStream.
            /// </summary>
            /// <param name="outputStream">The stream that will contain the
            /// encrypted data when this method returns.</param>
            /// <param name="fileName">FileInfo of the file to encrypt</param>
            public void Encrypt(Stream outputStream, FileInfo unencryptedFileInfo)
            {
                if (outputStream == null)
                {
                    throw new ArgumentNullException("outputStream", "outputStream is null.");
                }
                if (unencryptedFileInfo == null)
                {
                    throw new ArgumentNullException("unencryptedFileInfo", "unencryptedFileInfo is null.");
                }
                if (!File.Exists(unencryptedFileInfo.FullName))
                {
                    throw new ArgumentException("File to encrypt not found.");
                }
                using (Stream encryptedOut = ChainEncryptedOut(outputStream))
                {
                    using (Stream literalOut = ChainLiteralOut(encryptedOut, unencryptedFileInfo))
                    using (FileStream inputFile = unencryptedFileInfo.OpenRead())
                    {
                        WriteOutput(literalOut, inputFile);
                    }
                }
            }
    
            private static void WriteOutput(Stream literalOut,
                FileStream inputFile)
            {
                int length = 0;
                byte[] buf = new byte[BufferSize];
                while ((length = inputFile.Read(buf, 0, buf.Length)) > 0)
                {
                    literalOut.Write(buf, 0, length);
                }
            }
    
            private Stream ChainEncryptedOut(Stream outputStream)
            {
                PgpEncryptedDataGenerator encryptedDataGenerator;
                encryptedDataGenerator =
                    new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.TripleDes,
                                                  new SecureRandom());
                encryptedDataGenerator.AddMethod(m_encryptionKeys.PublicKey);
                return encryptedDataGenerator.Open(outputStream, new byte[BufferSize]);
            }
    
            private static Stream ChainLiteralOut(Stream encryptedOut, FileInfo file)
            {
                PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
                return pgpLiteralDataGenerator.Open(encryptedOut, PgpLiteralData.Binary, 
    
    file);
                } 
    }
    

    当然,要运行这些代码,您必须在项目中包含 BouncyCastle library
    我已经测试了加密然后解密,它运行良好:)

    【讨论】:

    • 为什么是这个答案?这看起来像是使用预共享密钥的对称加密,而不是使用公钥/私钥的非对称加密。
    • 这是非对称加密,它适用于公钥/私钥。
    • 带有“SymmetricKeyAlgorithmTag.TripleDes”的部分可能......好吧......有点过时了。
    • PgpEncryptionKeys 类从何而来?
    • 如何加密字符串,而不是 FileInfo?
    【解决方案2】:

    这也许是一种更简洁的方法:


            var pkr = asciiPublicKeyToRing(ascfilein);
            if (pkr != null)
            {
                try
                {
                    EncryptFile(
                    tbUnencryptedFile.Text, tbEncryptedFile.Text, getFirstPublicEncryptionKeyFromRing(pkr), true, true);
    
                    MessageBox.Show("File Encrypted.");
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: " + ex.Message);
                }
            }
            else
            {
                 MessageBox.Show(ascfilein + " is not a public key.");
            }
    

        private PgpPublicKeyRing asciiPublicKeyToRing(string ascfilein)
        {
            using (Stream pubFis = File.OpenRead(ascfilein))
            {
                var pubArmoredStream = new ArmoredInputStream(pubFis);
    
                PgpObjectFactory pgpFact = new PgpObjectFactory(pubArmoredStream);
                Object opgp = pgpFact.NextPgpObject();
                var pkr = opgp as PgpPublicKeyRing;
                return pkr;
            }
        }
    
        private PgpPublicKey getFirstPublicEncryptionKeyFromRing(PgpPublicKeyRing pkr)
        {
            foreach (PgpPublicKey k in pkr.GetPublicKeys())
            {
                if (k.IsEncryptionKey)
                    return k;
            }
            throw new ArgumentException("Can't find encryption key in key ring.");
        }
    
        public static void EncryptFile(string inputFile, string outputFile, PgpPublicKey encKey, bool armor,
            bool withIntegrityCheck)
        {
            using (MemoryStream bOut = new MemoryStream())
            {
                PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
                PgpUtilities.WriteFileToLiteralData(comData.Open(bOut), PgpLiteralData.Binary,
                    new FileInfo(inputFile));
    
                comData.Close();
                PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Aes256,
                    withIntegrityCheck, new SecureRandom());
    
                cPk.AddMethod(encKey);
                byte[] bytes = bOut.ToArray();
    
                using (Stream outputStream = File.Create(outputFile))
                {
                    if (armor)
                    {
                        using (ArmoredOutputStream armoredStream = new ArmoredOutputStream(outputStream))
                        using (Stream cOut = cPk.Open(armoredStream, bytes.Length))
                        {
                            cOut.Write(bytes, 0, bytes.Length);
                        }
                    }
                    else
                    {
                        using (Stream cOut = cPk.Open(outputStream, bytes.Length))
                        {
                            cOut.Write(bytes, 0, bytes.Length);
                        }
                    }
                }
            }
        }
    

    【讨论】:

      【解决方案3】:

      你看过bouncycastle pgp了吗? http://www.bouncycastle.org/

      这里有一个加密取自 BouncyCastle 站点的文件的源示例:Need example for BouncyCastle PGP File encryption in C#

      【讨论】:

      • 什么是装甲和完整性检查?还有密码吗?
      • Armor 是“ASCII 编码的二进制数据”的一种奇特说法,意思是你可以加密图片和 word 文档。
      【解决方案4】:

      如果你想在dotnet core中同时做加密和解密,这是我关注的文章:https://nightbaker.github.io/pgp/cryptography/.net/core/2019/02/08/pgp-encryption/

      加密部分不需要私钥。

      所有学分归原作者 NightBaker 所有。

      Install-Package  BouncyCastle.NetCore
      Install-Package  BouncyCastle.NetCoreSdk
      
      public class Pgp
      {
          public static void EncryptFile(
              string outputFileName,
              string inputFileName,
              string encKeyFileName,
              bool armor,
              bool withIntegrityCheck)
          {
              PgpPublicKey encKey = PgpExampleUtilities.ReadPublicKey(encKeyFileName);
      
              using (Stream output = File.Create(outputFileName))
              {
                  EncryptFile(output, inputFileName, encKey, armor, withIntegrityCheck);
              }
          }
      
          private static void EncryptFile(
              Stream outputStream,
              string fileName,
              PgpPublicKey encKey,
              bool armor,
              bool withIntegrityCheck)
          {
              if (armor)
              {
                  outputStream = new ArmoredOutputStream(outputStream);
              }
      
              try
              {
                  byte[] bytes = PgpExampleUtilities.CompressFile(fileName, CompressionAlgorithmTag.Zip);
      
                  PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(
                      SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
                  encGen.AddMethod(encKey);
      
                  Stream cOut = encGen.Open(outputStream, bytes.Length);
      
                  cOut.Write(bytes, 0, bytes.Length);
                  cOut.Close();
      
                  if (armor)
                  {
                      outputStream.Close();
                  }
              }
              catch (PgpException e)
              {
                  Console.Error.WriteLine(e);
      
                  Exception underlyingException = e.InnerException;
                  if (underlyingException != null)
                  {
                      Console.Error.WriteLine(underlyingException.Message);
                      Console.Error.WriteLine(underlyingException.StackTrace);
                  }
              }
          }
      }
      
      public class PgpExampleUtilities
      {
          internal static PgpPublicKey ReadPublicKey(string fileName)
          {
              using (Stream keyIn = File.OpenRead(fileName))
              {
                  return ReadPublicKey(keyIn);
              }
          }
      
          internal static PgpPublicKey ReadPublicKey(Stream input)
          {
              PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(
                  PgpUtilities.GetDecoderStream(input));
      
              //
              // we just loop through the collection till we find a key suitable for encryption, in the real
              // world you would probably want to be a bit smarter about this.
              //
      
              foreach (PgpPublicKeyRing keyRing in pgpPub.GetKeyRings())
              {
                  foreach (PgpPublicKey key in keyRing.GetPublicKeys())
                  {
                      if (key.IsEncryptionKey)
                      {
                          return key;
                      }
                  }
              }
      
              throw new ArgumentException("Can't find encryption key in key ring.");
          }
      
      
          internal static byte[] CompressFile(string fileName, CompressionAlgorithmTag algorithm)
          {
              MemoryStream bOut = new MemoryStream();
              PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(algorithm);
              PgpUtilities.WriteFileToLiteralData(comData.Open(bOut), PgpLiteralData.Binary,
                  new FileInfo(fileName));
              comData.Close();
              return bOut.ToArray();
          }
      }
      

      用法:

      Pgp.EncryptFile("Resources/output.txt", "Resources/input.txt", "Resources/publicKey.txt", true, true);
      

      【讨论】:

      • 欢迎提供解决方案链接,但请确保您的答案在没有它的情况下有用:add context around the link 这样您的其他用户就会知道它是什么以及为什么会出现,然后引用最相关的您链接到的页面的一部分,以防目标页面不可用。 Answers that are little more than a link may be deleted.
      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
      • 您不能只是从第三方文章中复制代码并将其呈现为您自己的答案。你写的答案应该是你自己的。允许有选择地引用归属来源,只要你明确它是一个引用,只要它不是你的答案的大部分。
      【解决方案5】:

      如果您正在寻找一个简单的 dotnet 库来进行 pgp 加密,请查看 PgpCore。它是Bouncy Castle 的封装——只是让它比需要了解 Bouncy Castle 的内部结构更容易一些。

      【讨论】:

        猜你喜欢
        • 2020-12-13
        • 2020-01-08
        • 1970-01-01
        • 1970-01-01
        • 2012-04-13
        • 1970-01-01
        • 1970-01-01
        • 2011-05-12
        • 1970-01-01
        相关资源
        最近更新 更多