2012-04-18 51 views
11

私は本当にこれに苦しんでいます。私はC#でBouncyCastleを使って文字列を暗号化して解読する必要があります。 私は本当に自分でこれをやろうとしました。 自分の鍵(私的および公的)を作成することができました。PGP暗号化と復号化

私は大学で新しくなっていることに注意してください。

+4

を私はあなたにこれを実行しようとしてくれてうれしいですあなた自身が、あなたが試したものについていくつかの洞察力を与える必要があります。どのような仕事をしていますか?何がうまくいかなかったのですか?コードを表示してください。 – Robaticus

+0

そのライブラリを使用する必要がありますか、.NET暗号化フレームワークを使用できますか? –

+0

基本的にはPGPを使うだけです...私はちょっとした例が必要です。私は今一週間これをしています。そして、一週間で私が正しいことができるのは鍵を作ることでした。 –

答えて

27

PGPに弾力のある城を使用した例を見つけるにはしばらく時間がかかりました。これは私が生産で使うものです。私はそれが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 
    } 
} 

そして、それは使用しています:

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

暗号化をファイル:

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

は、ファイル復号化:

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

よろしくお願いします。 – dimoss

+0

私は質問があります、それは圧迫することなく暗号化することは可能ですか? – Lisa

+1

@Lisa - 私は100%確実ではありません。おそらくコミュニティの誰かが助けることができるかどうかを知るために、それを公式質問として尋ねるべきでしょう。 –