2012-04-18 48 views
11

Tôi thực sự đang đấu tranh với điều này, tôi cần mã hóa và giải mã một chuỗi bằng BouncyCastle trong C#. Tôi thực sự đã cố gắng làm điều này một mình. Tôi đã quản lý để tạo khóa riêng của mình (riêng tư và công khai).PGP Mã hóa và Giải mã

Hãy nhớ rằng tôi mới ra trường.

+4

Tôi rất vui vì bạn đã cố gắng để làm điều này trên của bạn của riêng bạn, nhưng bạn cần cung cấp cho chúng tôi một số thông tin chi tiết về những gì bạn đã thử. Những gì loại-làm việc? Cái gì không hiệu quả? Hiển thị mã cho chúng tôi. – Robaticus

+0

Bạn có phải sử dụng thư viện đó hoặc bạn có thể sử dụng khung công tác crypto .NET không? –

+0

Về cơ bản tôi chỉ cần sử dụng PGP ... Tôi chỉ cần một số ví dụ, tôi đã ở đây một tuần nay .. Và trong một tuần tất cả những gì tôi có thể làm là tạo ra chìa khóa. –

Trả lời

27

Tôi mất một thời gian để tìm một ví dụ điển hình về việc sử dụng lâu đài bouncy cho PGP. Đây là những gì tôi sử dụng trong sản xuất. Tôi chắc chắn nó có nguồn gốc từ here.

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

namespace FileEncryptionTasks.Helpers.PGP 
{ 
    public static class PGPEncryptDecrypt 
    { 
     private const int BufferSize = 0x10000; // should always be power of 2 

     #region Encrypt 

     /* 
     * Encrypt the file. 
     */ 

     public static void EncryptFile(string inputFile, string outputFile, string publicKeyFile, bool armor, bool withIntegrityCheck) 
     { 
      try 
      { 
       using (Stream publicKeyStream = File.OpenRead(publicKeyFile)) 
       { 
        PgpPublicKey encKey = ReadPublicKey(publicKeyStream); 

        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.Cast5, 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); 
           } 
          } 
         } 
        } 
       } 
      } 
      catch (PgpException e) 
      { 
       throw; 
      } 
     } 

     #endregion Encrypt 

     #region Encrypt and Sign 

     /* 
     * Encrypt and sign the file pointed to by unencryptedFileInfo and 
     */ 

     public static void EncryptAndSign(string inputFile, string outputFile, string publicKeyFile, string privateKeyFile, string passPhrase, bool armor) 
     { 
      PgpEncryptionKeys encryptionKeys = new PgpEncryptionKeys(publicKeyFile, privateKeyFile, passPhrase); 

      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("Invalid Pass Phrase."); 

      if (encryptionKeys == null) 
       throw new ArgumentNullException("Encryption Key not found."); 

      using (Stream outputStream = File.Create(outputFile)) 
      { 
       if (armor) 
        using (ArmoredOutputStream armoredOutputStream = new ArmoredOutputStream(outputStream)) 
        { 
         OutputEncrypted(inputFile, armoredOutputStream, encryptionKeys); 
        } 
       else 
        OutputEncrypted(inputFile, outputStream, encryptionKeys); 
      } 
     } 

     private static void OutputEncrypted(string inputFile, Stream outputStream, PgpEncryptionKeys encryptionKeys) 
     { 
      using (Stream encryptedOut = ChainEncryptedOut(outputStream, encryptionKeys)) 
      { 
       FileInfo unencryptedFileInfo = new FileInfo(inputFile); 
       using (Stream compressedOut = ChainCompressedOut(encryptedOut)) 
       { 
        PgpSignatureGenerator signatureGenerator = InitSignatureGenerator(compressedOut, encryptionKeys); 
        using (Stream literalOut = ChainLiteralOut(compressedOut, unencryptedFileInfo)) 
        { 
         using (FileStream inputFileStream = unencryptedFileInfo.OpenRead()) 
         { 
          WriteOutputAndSign(compressedOut, literalOut, inputFileStream, signatureGenerator); 
          inputFileStream.Close(); 
         } 
        } 
       } 
      } 
     } 

     private static void WriteOutputAndSign(Stream compressedOut, Stream literalOut, FileStream inputFile, PgpSignatureGenerator signatureGenerator) 
     { 
      int length = 0; 
      byte[] buf = new byte[BufferSize]; 
      while ((length = inputFile.Read(buf, 0, buf.Length)) > 0) 
      { 
       literalOut.Write(buf, 0, length); 
       signatureGenerator.Update(buf, 0, length); 
      } 
      signatureGenerator.Generate().Encode(compressedOut); 
     } 

     private static Stream ChainEncryptedOut(Stream outputStream, PgpEncryptionKeys m_encryptionKeys) 
     { 
      PgpEncryptedDataGenerator encryptedDataGenerator; 
      encryptedDataGenerator = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.TripleDes, new SecureRandom()); 
      encryptedDataGenerator.AddMethod(m_encryptionKeys.PublicKey); 
      return encryptedDataGenerator.Open(outputStream, new byte[BufferSize]); 
     } 

     private static Stream ChainCompressedOut(Stream encryptedOut) 
     { 
      PgpCompressedDataGenerator compressedDataGenerator = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip); 
      return compressedDataGenerator.Open(encryptedOut); 
     } 

     private static Stream ChainLiteralOut(Stream compressedOut, FileInfo file) 
     { 
      PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator(); 
      return pgpLiteralDataGenerator.Open(compressedOut, PgpLiteralData.Binary, file); 
     } 

     private static PgpSignatureGenerator InitSignatureGenerator(Stream compressedOut, PgpEncryptionKeys m_encryptionKeys) 
     { 
      const bool IsCritical = false; 
      const bool IsNested = false; 
      PublicKeyAlgorithmTag tag = m_encryptionKeys.SecretKey.PublicKey.Algorithm; 
      PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(tag, HashAlgorithmTag.Sha1); 
      pgpSignatureGenerator.InitSign(PgpSignature.BinaryDocument, m_encryptionKeys.PrivateKey); 
      foreach (string userId in m_encryptionKeys.SecretKey.PublicKey.GetUserIds()) 
      { 
       PgpSignatureSubpacketGenerator subPacketGenerator = new PgpSignatureSubpacketGenerator(); 
       subPacketGenerator.SetSignerUserId(IsCritical, userId); 
       pgpSignatureGenerator.SetHashedSubpackets(subPacketGenerator.Generate()); 
       // Just the first one! 
       break; 
      } 
      pgpSignatureGenerator.GenerateOnePassVersion(IsNested).Encode(compressedOut); 
      return pgpSignatureGenerator; 
     } 

     #endregion Encrypt and Sign 

     #region Decrypt 

     /* 
     * decrypt a given stream. 
     */ 

     public static void Decrypt(string inputfile, string privateKeyFile, string passPhrase, string outputFile) 
     { 
      if (!File.Exists(inputfile)) 
       throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputfile)); 

      if (!File.Exists(privateKeyFile)) 
       throw new FileNotFoundException(String.Format("Private Key File [{0}] not found.", privateKeyFile)); 

      if (String.IsNullOrEmpty(outputFile)) 
       throw new ArgumentNullException("Invalid Output file path."); 

      using (Stream inputStream = File.OpenRead(inputfile)) 
      { 
       using (Stream keyIn = File.OpenRead(privateKeyFile)) 
       { 
        Decrypt(inputStream, keyIn, passPhrase, outputFile); 
       } 
      } 
     } 

     /* 
     * decrypt a given stream. 
     */ 

     public static void Decrypt(Stream inputStream, Stream privateKeyStream, string passPhrase, string outputFile) 
     { 
      try 
      { 
       PgpObjectFactory pgpF = null; 
       PgpEncryptedDataList enc = null; 
       PgpObject o = null; 
       PgpPrivateKey sKey = null; 
       PgpPublicKeyEncryptedData pbe = null; 
       PgpSecretKeyRingBundle pgpSec = null; 

       pgpF = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream)); 
       // find secret key 
       pgpSec = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream)); 

       if (pgpF != null) 
        o = pgpF.NextPgpObject(); 

       // the first object might be a PGP marker packet. 
       if (o is PgpEncryptedDataList) 
        enc = (PgpEncryptedDataList)o; 
       else 
        enc = (PgpEncryptedDataList)pgpF.NextPgpObject(); 

       // decrypt 
       foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects()) 
       { 
        sKey = FindSecretKey(pgpSec, pked.KeyId, passPhrase.ToCharArray()); 

        if (sKey != null) 
        { 
         pbe = pked; 
         break; 
        } 
       } 

       if (sKey == null) 
        throw new ArgumentException("Secret key for message not found."); 

       PgpObjectFactory plainFact = null; 

       using (Stream clear = pbe.GetDataStream(sKey)) 
       { 
        plainFact = new PgpObjectFactory(clear); 
       } 

       PgpObject message = plainFact.NextPgpObject(); 

       if (message is PgpCompressedData) 
       { 
        PgpCompressedData cData = (PgpCompressedData)message; 
        PgpObjectFactory of = null; 

        using (Stream compDataIn = cData.GetDataStream()) 
        { 
         of = new PgpObjectFactory(compDataIn); 
        } 

        message = of.NextPgpObject(); 
        if (message is PgpOnePassSignatureList) 
        { 
         message = of.NextPgpObject(); 
         PgpLiteralData Ld = null; 
         Ld = (PgpLiteralData)message; 
         using (Stream output = File.Create(outputFile)) 
         { 
          Stream unc = Ld.GetInputStream(); 
          Streams.PipeAll(unc, output); 
         } 
        } 
        else 
        { 
         PgpLiteralData Ld = null; 
         Ld = (PgpLiteralData)message; 
         using (Stream output = File.Create(outputFile)) 
         { 
          Stream unc = Ld.GetInputStream(); 
          Streams.PipeAll(unc, output); 
         } 
        } 
       } 
       else if (message is PgpLiteralData) 
       { 
        PgpLiteralData ld = (PgpLiteralData)message; 
        string outFileName = ld.FileName; 

        using (Stream fOut = File.Create(outputFile)) 
        { 
         Stream unc = ld.GetInputStream(); 
         Streams.PipeAll(unc, fOut); 
        } 
       } 
       else if (message is PgpOnePassSignatureList) 
        throw new PgpException("Encrypted message contains a signed message - not literal data."); 
       else 
        throw new PgpException("Message is not a simple encrypted file - type unknown."); 

       #region commented code 

       //if (pbe.IsIntegrityProtected()) 
       //{ 
       // if (!pbe.Verify()) 
       //  msg = "message failed integrity check."; 
       // //Console.Error.WriteLine("message failed integrity check"); 
       // else 
       //  msg = "message integrity check passed."; 
       // //Console.Error.WriteLine("message integrity check passed"); 
       //} 
       //else 
       //{ 
       // msg = "no message integrity check."; 
       // //Console.Error.WriteLine("no message integrity check"); 
       //} 

       #endregion commented code 
      } 
      catch (PgpException ex) 
      { 
       throw; 
      } 
     } 

     #endregion Decrypt 

     #region Private helpers 

     /* 
     * A simple routine that opens a key ring file and loads the first available key suitable for encryption. 
     */ 

     private static PgpPublicKey ReadPublicKey(Stream inputStream) 
     { 
      inputStream = PgpUtilities.GetDecoderStream(inputStream); 

      PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(inputStream); 

      // 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. 
      // iterate through the key rings. 
      foreach (PgpPublicKeyRing kRing in pgpPub.GetKeyRings()) 
      { 
       foreach (PgpPublicKey k in kRing.GetPublicKeys()) 
       { 
        if (k.IsEncryptionKey) 
         return k; 
       } 
      } 

      throw new ArgumentException("Can't find encryption key in key ring."); 
     } 

     /* 
     * Search a secret key ring collection for a secret key corresponding to keyId if it exists. 
     */ 

     private static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec, long keyId, char[] pass) 
     { 
      PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyId); 

      if (pgpSecKey == null) 
       return null; 

      return pgpSecKey.ExtractPrivateKey(pass); 
     } 

     #endregion Private helpers 
    } 
} 

Và nó sử dụng:

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

namespace FileEncryptionTasks.Helpers.PGP 
{ 
    public class PgpEncryptionKeys 
    { 
     public PgpPublicKey PublicKey { get; private set; } 

     public PgpPrivateKey PrivateKey { get; private set; } 

     public PgpSecretKey SecretKey { get; private set; } 

     /// <summary> 
     /// Initializes a new instance of the EncryptionKeys class. 
     /// Two keys are required to encrypt and sign data. Your private key and the recipients public key. 
     /// The data is encrypted with the recipients public key and signed with your private key. 
     /// </summary> 
     /// <param name="publicKeyPath">The key used to encrypt the data</param> 
     /// <param name="privateKeyPath">The key used to sign the data.</param> 
     /// <param name="passPhrase">The (your) password required to access the private key</param> 
     /// <exception cref="ArgumentException">Public key not found. Private key not found. Missing password</exception> 
     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 = ReadPublicKey(publicKeyPath); 
      SecretKey = ReadSecretKey(privateKeyPath); 
      PrivateKey = ReadPrivateKey(passPhrase); 
     } 

     #region Secret Key 

     private PgpSecretKey ReadSecretKey(string privateKeyPath) 
     { 
      using (Stream keyIn = File.OpenRead(privateKeyPath)) 
      { 
       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> 
     /// Return the first key we can use to encrypt. 
     /// Note: A file can contain multiple keys (stored in "key rings") 
     /// </summary> 
     private PgpSecretKey GetFirstSecretKey(PgpSecretKeyRingBundle secretKeyRingBundle) 
     { 
      foreach (PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings()) 
      { 
       PgpSecretKey key = kRing.GetSecretKeys() 
        .Cast<PgpSecretKey>() 
        .Where(k => k.IsSigningKey) 
        .FirstOrDefault(); 
       if (key != null) 
        return key; 
      } 
      return null; 
     } 

     #endregion Secret Key 

     #region Public Key 

     private PgpPublicKey ReadPublicKey(string publicKeyPath) 
     { 
      using (Stream keyIn = File.OpenRead(publicKeyPath)) 
      { 
       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."); 
     } 

     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; 
     } 

     #endregion Public Key 

     #region Private Key 

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

     #endregion Private Key 
    } 
} 

Mã hóa một tập tin:

PGPEncryptDecrypt.EncryptFile(inputFileName, 
           outputFileName, 
           recipientKeyFileName, 
           shouldArmor, 
           shouldCheckIntegrity); 

Giải mã một tập tin:

PGPEncryptDecrypt.Decrypt(inputFileName, 
          privateKeyFileName, 
          passPhrase, 
          outputFileName); 
+0

Cảm ơn bạn đã làm việc rất tốt cho tôi! – dimoss

+0

Tôi có một câu hỏi, có thể mã hóa mà không cần comperessing không? – Lisa

+1

@Lisa - Tôi không chắc chắn 100%. Có lẽ bạn nên hỏi nó như một câu hỏi chính thức để xem liệu có ai trong cộng đồng có thể giúp đỡ hay không. –